home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / extras / Direct3D / Tools / Maya25 / xportTranslator.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-08  |  91.4 KB  |  3,942 lines

  1. // TBD    
  2. //        - magic number "xof";
  3. //        - skinning for bezier patches????
  4. //        - adjust normals according to tweaks
  5. //        - test animation with different models (hierarchies, etc.)
  6. //        - support for single-sided vs. double sided
  7. //        - check whether there really is vertex coloring info
  8. //        - make sure that shape names are unique and valid
  9. //        - option to export only selected items
  10. //        - uncomment vertex coloring info
  11.  
  12.  
  13. // DONE
  14. //        - multiply envelope by tweaks
  15. //        - export bicubic bezier patches
  16. //        - relative pathnames for textures
  17. //        - make animation optional
  18. //        - speed up animation by rearranging loops
  19. //        - error handling
  20. //        - free Mesh::rgBones[iBone].m_szName
  21. //        - option to flip UV tex coords
  22. //        - option for animation transforms a) ONLY at keyframes or b) at EVERY frame
  23. //        - dialog box interface
  24. //        - option for Text/Binary/Compressed mode
  25.  
  26. // BUGS
  27. //        - wierd errors loading cowboy.        - Dt library crashes during it's initialization
  28.  
  29.  
  30.  
  31.  
  32.  
  33. #include "MyDt.h"
  34. #include "MyAssert.h"
  35.  
  36. #include "xportTranslator.h"
  37.  
  38. #include <iostream.h>
  39.  
  40.  
  41.  
  42. // DirectX File Format
  43. #include <dxfile.h>
  44.  
  45. #include <initguid.h>
  46. #include <rmxfguid.h>
  47. #include <rmxftmpl.h>
  48.  
  49. // Additional X-file Templates
  50. #include "xskinexptemplates.h"
  51.  
  52. const GUID* aIds[] = {&DXFILEOBJ_XSkinMeshHeader,
  53.                       &DXFILEOBJ_VertexDuplicationIndices,
  54.                       &DXFILEOBJ_SkinWeights};
  55.  
  56.  
  57. // Maya API
  58. #include <maya/MFnPlugin.h>
  59. #include <maya/MSimple.h>
  60. #include <maya/MObject.h>
  61. #include <maya/MColor.h>
  62. #include <maya/MMatrix.h>
  63. #include <maya/MDagPath.h>
  64. #include <maya/MTime.h>
  65. #include <maya/MAnimControl.h>
  66.  
  67. #include <maya/MDataBlock.h>
  68. #include <maya/MDataHandle.h>
  69.  
  70. #include <maya/MIntArray.h>
  71. #include <maya/MFloatArray.h>
  72. #include <maya/MFloatVectorArray.h>
  73. #include <maya/MFloatPointArray.h>
  74. #include <maya/MPointArray.h>
  75. #include <maya/MObjectArray.h>
  76. #include <maya/MDagPathArray.h>
  77. #include <maya/MPlugArray.h>
  78. #include <maya/MSelectionList.h>
  79.  
  80. #include <maya/MFnMatrixData.h>
  81. #include <maya/MFnMeshData.h>
  82. #include <maya/MFnDoubleArrayData.h>
  83. #include <maya/MFnVectorArrayData.h>
  84.  
  85. #include <maya/MFnSingleIndexedComponent.h>
  86. #include <maya/MFnDoubleIndexedComponent.h>
  87. #include <maya/MFnSet.h>
  88. #include <maya/MFnTypedAttribute.h>
  89. #include <maya/MFnSkinCluster.h>
  90. #include <maya/MFnWeightGeometryFilter.h>
  91. #include <maya/MFnDagNode.h>
  92. #include <maya/MFnIKJoint.h>
  93. #include <maya/MFnMesh.h>
  94. #include <maya/MFnNurbsSurface.h>
  95. #include <maya/MFnLambertShader.h>
  96.  
  97. #include <maya/MItDependencyNodes.h>
  98. #include <maya/MItGeometry.h>
  99.  
  100.  
  101.  
  102. extern    StringTable g_Strings;
  103.  
  104.  
  105. // Dt API
  106. #include <MDt.h>
  107. #include <MDtExt.h>
  108.  
  109.  
  110. // Options
  111.  
  112. DXFILEFORMAT            g_FileFormat;
  113. extern    bool            g_bExportAnimation;
  114. extern    bool            g_bKeyframeAnimation;
  115. extern    bool            g_bAnimateEverything;
  116. extern    int                g_iFrameStep;
  117. extern    int                g_iFlipU;
  118. extern    int                g_iFlipV;
  119. extern    bool            g_bRelativeTexFile;
  120. extern    bool            g_bExportPatches;
  121.  
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133. HRESULT    AddAnim
  134.         (
  135.             Anim*                    pAnim, 
  136.             LPDIRECTXFILEDATA        pAnimSetObject, 
  137.             LPDIRECTXFILESAVEOBJECT    pxofSave
  138.         ) 
  139. {
  140.     HRESULT                hr                            = S_OK;
  141.     
  142.     LPDIRECTXFILEDATA    pAnimDataObject                = NULL;
  143.  
  144.     LPDIRECTXFILEDATA    pQuaternionKeyDataObject    = NULL;
  145.     LPDIRECTXFILEDATA    pScaleKeyDataObject            = NULL;
  146.     LPDIRECTXFILEDATA    pPositionKeyDataObject        = NULL;
  147.  
  148.     PBYTE                pbQuaternionKeyData            = NULL;
  149.     PBYTE                pbScaleKeyData                = NULL;
  150.     PBYTE                pbPositionKeyData            = NULL;
  151.  
  152.  
  153.  
  154.     INIT;
  155.  
  156.  
  157.  
  158.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMAnimation, NULL, NULL, 0, NULL, &pAnimDataObject),
  159.                 "Could not create pAnimDataObject.");
  160.  
  161.  
  162.     int        cbQuaternionKeySize    = sizeof(DWORD)                                                // keyType
  163.                                 + sizeof(DWORD)                                                // nKeys
  164.                                 + pAnim->m_cKeys 
  165.                                     * (sizeof(DWORD) + sizeof(DWORD) + 4 * sizeof(float));    // keys[nKeys]
  166.  
  167.  
  168.     PBYTE    pbQuaternionKeyCurr    = pbQuaternionKeyData    = new BYTE[cbQuaternionKeySize];
  169.  
  170.     ASSERT(pbQuaternionKeyData,
  171.                 "Could not allocate memory for pbQuaternionKeyData.");
  172.  
  173.  
  174.     int        cbScaleKeySize    = sizeof(DWORD)                                                    // keyType
  175.                             + sizeof(DWORD)                                                    // nKeys
  176.                             + pAnim->m_cKeys 
  177.                                 * (sizeof(DWORD) + sizeof(DWORD) + 3 * sizeof(float));        // keys[nKeys]
  178.  
  179.     PBYTE    pbScaleKeyCurr    = pbScaleKeyData    = new BYTE[cbScaleKeySize];
  180.  
  181.     ASSERT(pbScaleKeyData,
  182.                 "Could not allocate memory for pbScaleKeyData.");
  183.  
  184.  
  185.     int        cbPositionKeySize    = sizeof(DWORD)                                                // keyType
  186.                                 + sizeof(DWORD)                                                // nKeys
  187.                                 + pAnim->m_cKeys 
  188.                                     * (sizeof(DWORD) + sizeof(DWORD) + 3 * sizeof(float));    // keys[nKeys]
  189.  
  190.     PBYTE    pbPositionKeyCurr    = pbPositionKeyData    = new BYTE[cbPositionKeySize];
  191.  
  192.     ASSERT(pbPositionKeyData,
  193.                 "Could not allocate memory for pbPositionKeyData.");
  194.  
  195.  
  196.     // keyType
  197.     WRITE_DWORD(pbQuaternionKeyCurr,    ((DWORD)0));
  198.     WRITE_DWORD(pbScaleKeyCurr,            ((DWORD)1));
  199.     WRITE_DWORD(pbPositionKeyCurr,        ((DWORD)2));
  200.  
  201.     // nKeys
  202.     WRITE_DWORD(pbQuaternionKeyCurr,    ((DWORD)pAnim->m_cKeys));
  203.     WRITE_DWORD(pbScaleKeyCurr,            ((DWORD)pAnim->m_cKeys));
  204.     WRITE_DWORD(pbPositionKeyCurr,        ((DWORD)pAnim->m_cKeys));
  205.  
  206.     // keys[nKeys]
  207.     for (int iKey = 0; iKey < pAnim->m_cKeys; iKey++) 
  208.     {
  209.         // time
  210.         WRITE_DWORD(pbQuaternionKeyCurr,    ((DWORD)pAnim->m_rgKeys[iKey].m_iFrame));
  211.         WRITE_DWORD(pbScaleKeyCurr,            ((DWORD)pAnim->m_rgKeys[iKey].m_iFrame));
  212.         WRITE_DWORD(pbPositionKeyCurr,        ((DWORD)pAnim->m_rgKeys[iKey].m_iFrame));
  213.  
  214.  
  215.         // nValues
  216.         WRITE_DWORD(pbQuaternionKeyCurr,    ((DWORD)4));
  217.         WRITE_DWORD(pbScaleKeyCurr,            ((DWORD)3));
  218.         WRITE_DWORD(pbPositionKeyCurr,        ((DWORD)3));
  219.  
  220.         // values
  221.         WRITE_FLOAT(pbQuaternionKeyCurr,   -pAnim->m_rgKeys[iKey].m_rgfQuaternion[0]);
  222.         WRITE_FLOAT(pbQuaternionKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfQuaternion[1]);
  223.         WRITE_FLOAT(pbQuaternionKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfQuaternion[2]);
  224.         WRITE_FLOAT(pbQuaternionKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfQuaternion[3]);
  225.  
  226.         WRITE_FLOAT(pbScaleKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfScale[0]);
  227.         WRITE_FLOAT(pbScaleKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfScale[1]);
  228.         WRITE_FLOAT(pbScaleKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfScale[2]);
  229.  
  230.         WRITE_FLOAT(pbPositionKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfPosition[0]);
  231.         WRITE_FLOAT(pbPositionKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfPosition[1]);
  232.         WRITE_FLOAT(pbPositionKeyCurr,    pAnim->m_rgKeys[iKey].m_rgfPosition[2]);
  233.     }
  234.  
  235.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMAnimationKey, NULL, NULL, cbQuaternionKeySize, pbQuaternionKeyData, &pQuaternionKeyDataObject),
  236.                 "Could not create pQuaternionKeyDataObject.");
  237.  
  238.  
  239.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMAnimationKey, NULL, NULL, cbScaleKeySize, pbScaleKeyData, &pScaleKeyDataObject),
  240.                 "Could not create pScaleKeyDataObject.");
  241.  
  242.  
  243.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMAnimationKey, NULL, NULL, cbPositionKeySize, pbPositionKeyData, &pPositionKeyDataObject),
  244.                 "Could not create pPositionKeyDataObject.");
  245.  
  246.  
  247.     HR_ATTEMPT(pAnimDataObject->AddDataReference(pAnim->m_szName, NULL),
  248.                 "Could not add data reference to pAnimDataObject.");
  249.  
  250.     HR_ATTEMPT(pAnimDataObject->AddDataObject(pQuaternionKeyDataObject),
  251.                 "Could not add pQuaternionKeyDataObject to pAnimDataObject.");
  252.  
  253.  
  254.     HR_ATTEMPT(pAnimDataObject->AddDataObject(pScaleKeyDataObject),
  255.                 "Could not add pScaleKeyDataObject to pAnimDataObject.");
  256.  
  257.     
  258.     HR_ATTEMPT(pAnimDataObject->AddDataObject(pPositionKeyDataObject),
  259.                 "Could not add pPositionKeyDataObject to pAnimDataObject.");
  260.  
  261.  
  262.  
  263.     HR_ATTEMPT(pAnimSetObject->AddDataObject(pAnimDataObject),
  264.                 "Could not add pAnimDataObject to pAnimSetObject.");
  265.  
  266.  
  267.  
  268.     EXIT;
  269.  
  270.  
  271.  
  272.     delete[] pbQuaternionKeyData;
  273.  
  274.     delete[] pbScaleKeyData;
  275.     
  276.     delete[] pbPositionKeyData;
  277.  
  278.  
  279.     if (pQuaternionKeyDataObject)
  280.         pQuaternionKeyDataObject->Release();
  281.  
  282.     if (pScaleKeyDataObject)
  283.         pScaleKeyDataObject->Release();
  284.  
  285.     if (pPositionKeyDataObject)
  286.         pPositionKeyDataObject->Release();
  287.  
  288.     if (pAnimDataObject)
  289.         pAnimDataObject->Release();
  290.  
  291.  
  292.     return hr;
  293. }
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304. HRESULT    loadAllAnims
  305.         (
  306.             Anim*    rgAnims
  307.         ) 
  308. {
  309.     HRESULT    hr    = S_OK;
  310.  
  311.     cout << "\treading at intervals of " << g_iFrameStep << " frame(s)" << endl;
  312.  
  313.     // calculate the frames per second
  314.     int    iFPS    = 1;
  315.  
  316.     switch(MTime::uiUnit()) 
  317.     {
  318.         case MTime::kSeconds:        // 1 fps
  319.             iFPS    = 1;
  320.             break;
  321.         case MTime::kMilliseconds:    // 1000 fps
  322.             iFPS    = 1000;
  323.             break;
  324.         case MTime::kGames:            // 15 fps
  325.             iFPS    = 15;
  326.             break;
  327.         case MTime::kFilm:            // 24 fps
  328.             iFPS    = 24;
  329.             break;
  330.         case MTime::kPALFrame:        // 25 fps
  331.             iFPS    = 25;
  332.             break;
  333.         case MTime::kNTSCFrame:        // 30 fps
  334.             iFPS    = 30;
  335.             break;
  336.         case MTime::kShowScan:        // 48 fps
  337.             iFPS    = 48;
  338.             break;
  339.         case MTime::kPALField:        // 50 fps
  340.             iFPS    = 50;
  341.             break;
  342.         case MTime::kNTSCField:        // 60 fps
  343.             iFPS    = 60;
  344.             break;
  345.         default:
  346.             iFPS    = 1;
  347.             break;
  348.     };
  349.  
  350.     float fTimeFactor    = 3600.0f / (float)iFPS;
  351.  
  352.  
  353.     MTime    timeStart(MAnimControl::minTime().value(), MTime::uiUnit());
  354.     MTime    timeEnd(MAnimControl::maxTime().value(), MTime::uiUnit());
  355.     MTime    timeCurrent(MAnimControl::currentTime().value(), MTime::uiUnit());
  356.  
  357.  
  358.     DtFrameSetStart((int)timeStart.value());
  359.     DtFrameSetEnd((int)timeEnd.value());
  360.  
  361.  
  362.     int cShapes    = DtShapeGetCount();
  363.  
  364.  
  365.     MIntArray*    rgrgiKeys    = new MIntArray[cShapes];
  366.  
  367.  
  368.     for (int iShape = 0; iShape < cShapes; iShape++) 
  369.     {
  370.         rgAnims[iShape].m_szName    = new char[256];
  371.         rgAnims[iShape].m_cKeys        = 0;
  372.         rgAnims[iShape].m_rgKeys    = new Key[1 + (DtFrameGetEnd() - DtFrameGetStart() + 1) / g_iFrameStep];
  373.  
  374.         g_Strings.add(rgAnims[iShape].m_szName);
  375.  
  376.         char* szName;
  377.  
  378.         DtShapeGetName(iShape, &szName);
  379.  
  380.         strcpy(rgAnims[iShape].m_szName, szName);
  381.  
  382.         DtShapeGetTRSAnimKeys(iShape, &rgrgiKeys[iShape]);
  383.     }
  384.  
  385.     for (int iFrame = DtFrameGetStart(); iFrame <= DtFrameGetEnd(); iFrame += g_iFrameStep) 
  386.     {
  387.         DtFrameSet(iFrame);
  388.  
  389.         for (int iShape = 0; iShape < cShapes; iShape++) 
  390.         {
  391.             if (rgrgiKeys[iShape].length() > 0 || g_bAnimateEverything) 
  392.             {
  393.                 rgAnims[iShape].m_rgKeys[rgAnims[iShape].m_cKeys].m_iFrame    = (int)((float)iFrame * fTimeFactor);
  394.  
  395.                 float*    rgfTRS;
  396.  
  397.                 DtShapeGetMatrix(iShape, &rgfTRS);
  398.  
  399.                 DtMatrixGetTransforms(rgfTRS, 
  400.                                       rgAnims[iShape].m_rgKeys[rgAnims[iShape].m_cKeys].m_rgfPosition, 
  401.                                       rgAnims[iShape].m_rgKeys[rgAnims[iShape].m_cKeys].m_rgfScale, 
  402.                                       rgAnims[iShape].m_rgKeys[rgAnims[iShape].m_cKeys].m_rgfQuaternion, 
  403.                                       rgAnims[iShape].m_rgKeys[rgAnims[iShape].m_cKeys].m_rgfRotation);
  404.  
  405.                 rgAnims[iShape].m_cKeys++;
  406.             }
  407.         }
  408.     }
  409.  
  410.     DtFrameSet((int)timeCurrent.value());
  411.  
  412.     delete[] rgrgiKeys;
  413.  
  414.     return hr;
  415. }
  416.  
  417.  
  418.  
  419. void    freeAllAnims
  420.         (
  421.             Anim*    rgAnims
  422.         ) 
  423. {
  424.     for (int iShape = 0; iShape < DtShapeGetCount(); iShape++)
  425.         delete[] rgAnims[iShape].m_rgKeys;
  426. }
  427.  
  428.  
  429. HRESULT    loadAnim
  430.         (
  431.             int        iShape, 
  432.             Anim*    pAnim
  433.         ) 
  434. {
  435.     HRESULT    hr    = S_OK;
  436.  
  437.  
  438.     char*    szName;
  439.  
  440.     DtShapeGetName(iShape, &szName);
  441.  
  442.  
  443.     cout << "\treading " << szName << endl;
  444.  
  445.     int        cKeys    = 0;
  446.     Key*    rgKeys    = NULL;
  447.  
  448.  
  449.     MTime    timeStart(MAnimControl::minTime().value(), MTime::uiUnit());
  450.     MTime    timeEnd(MAnimControl::maxTime().value(), MTime::uiUnit());
  451.     MTime    timeCurrent(MAnimControl::currentTime().value(), MTime::uiUnit());
  452.  
  453.     MIntArray    rgiKeys;
  454.  
  455.     DtShapeGetTRSAnimKeys(iShape, &rgiKeys);
  456.  
  457.  
  458.     cKeys    = rgiKeys.length();
  459.  
  460.     if (cKeys > 0) 
  461.     {
  462.         DtFrameSetStart(rgiKeys[0]);
  463.         DtFrameSetEnd(rgiKeys[cKeys - 1]);
  464.  
  465.         // calculate the frames per second
  466.         int    iFPS    = 1;
  467.  
  468.         switch(MTime::uiUnit()) 
  469.         {
  470.             case MTime::kSeconds:        // 1 fps
  471.                 iFPS    = 1;
  472.                 break;
  473.             case MTime::kMilliseconds:    // 1000 fps
  474.                 iFPS    = 1000;
  475.                 break;
  476.             case MTime::kGames:            // 15 fps
  477.                 iFPS    = 15;
  478.                 break;
  479.             case MTime::kFilm:            // 24 fps
  480.                 iFPS    = 24;
  481.                 break;
  482.             case MTime::kPALFrame:        // 25 fps
  483.                 iFPS    = 25;
  484.                 break;
  485.             case MTime::kNTSCFrame:        // 30 fps
  486.                 iFPS    = 30;
  487.                 break;
  488.             case MTime::kShowScan:        // 48 fps
  489.                 iFPS    = 48;
  490.                 break;
  491.             case MTime::kPALField:        // 50 fps
  492.                 iFPS    = 50;
  493.                 break;
  494.             case MTime::kNTSCField:        // 60 fps
  495.                 iFPS    = 60;
  496.                 break;
  497.             default:
  498.                 iFPS    = 1;
  499.                 break;
  500.         };
  501.  
  502.  
  503.         float fTimeFactor    = 3600.0f / (float)iFPS;
  504.  
  505.         
  506.         rgKeys    = new Key[cKeys];
  507.  
  508.         for (int iKey = 0; iKey < cKeys; iKey++) 
  509.         {
  510.             rgKeys[iKey].m_iFrame    = (int)((float)rgiKeys[iKey] * fTimeFactor);
  511.  
  512.             DtFrameSet(rgiKeys[iKey]);
  513.  
  514.             float*    rgfTRS;
  515.  
  516.             DtShapeGetMatrix(iShape, &rgfTRS);
  517.  
  518.             DtMatrixGetTransforms(rgfTRS, rgKeys[iKey].m_rgfPosition, rgKeys[iKey].m_rgfScale, rgKeys[iKey].m_rgfQuaternion, rgKeys[iKey].m_rgfRotation);
  519.         }
  520.  
  521.         DtFrameSetStart((int)timeStart.value());
  522.         DtFrameSetEnd((int)timeEnd.value());
  523.         DtFrameSet((int)timeCurrent.value());
  524.     }
  525.  
  526.  
  527.     pAnim->m_szName    = new char[256];
  528.  
  529.     g_Strings.add(pAnim->m_szName);
  530.  
  531.     strcpy(pAnim->m_szName, szName);
  532.  
  533.     pAnim->m_cKeys    = cKeys; 
  534.     pAnim->m_rgKeys    = rgKeys;
  535.  
  536.  
  537.     return hr;
  538. }
  539.  
  540.  
  541.  
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550. void    freeAnim
  551.         (
  552.             Anim*    pAnim
  553.         ) 
  554. {
  555.     delete[] pAnim->m_rgKeys;
  556. }
  557.  
  558.  
  559.  
  560.  
  561. //    Assumes that the shape is indeed a patch mesh.  This can be checked using MyDtShapeIsPatchMesh
  562.  
  563. HRESULT    LoadPatchMesh
  564.         (
  565.             int        iShape, 
  566.             Mesh*    pShape
  567.         ) 
  568. {
  569.     HRESULT    hr        = S_OK;
  570.     MStatus    mStat    = MS::kSuccess;
  571.  
  572.     
  573.     // set up references
  574.  
  575.     Mesh::ShapeType&    kType        = pShape->m_kType;
  576.  
  577.     int&        cReps                = pShape->m_cReps;
  578.     Rep*&        rgReps                = pShape->m_rgReps;
  579.  
  580.     int&        cVertices            = pShape->m_cVertices;
  581.     DtVec3f*&    rgVertices            = pShape->m_rgVertices;
  582.  
  583.     int&        cNormals            = pShape->m_cNormals;
  584.     DtVec3f*&    rgNormals            = pShape->m_rgNormals;
  585.  
  586.     int&        cTexCoords            = pShape->m_cTexCoords;
  587.     DtVec2f*&    rgTexCoords            = pShape->m_rgTexCoords;
  588.  
  589.     int&        cVertexColors        = pShape->m_cVertexColors;
  590.     DtRGBA*&    rgVertexColors        = pShape->m_rgVertexColors;
  591.  
  592.  
  593.     int&        cFaces                = pShape->m_cFaces;
  594.     Face*&        rgFaces                = pShape->m_rgFaces;
  595.  
  596.     int&        cFaceIndices        = pShape->m_cFaceIndices;
  597.  
  598.     int&        cGroups                = pShape->m_cGroups;
  599.     Group*&        rgGroups            = pShape->m_rgGroups;
  600.  
  601.  
  602.     int&        cBones                = pShape->m_cBones;
  603.     Bone*&        rgBones                = pShape->m_rgBones;
  604.  
  605.     int&        cMaxBonesPerVertex    = pShape->m_cMaxBonesPerVertex;
  606.     int&        cMaxBonesPerFace    = pShape->m_cMaxBonesPerFace;
  607.  
  608.  
  609.  
  610.     INIT;        // begin error checking
  611.  
  612.     // ensure that shape is a nurbs surface
  613.     MObject    objNurb;
  614.  
  615.     DT_ATTEMPT(DtExt_ShapeGetShapeNode(iShape, objNurb));
  616.  
  617.     ASSERT(objNurb.hasFn(MFn::kNurbsSurface),    
  618.                 "Not a nurb surface");
  619.  
  620.     MFnNurbsSurface    fnNurb(objNurb);
  621.  
  622.     // ensure that surface is bicubic
  623.     ASSERT(fnNurb.degreeU() == 3 && fnNurb.degreeV() == 3,    
  624.                 "Not a bicubic surface");
  625.  
  626.     // ensure correct form in U and V 
  627.     int    kFormInU    = fnNurb.formInU();
  628.     int    kFormInV    = fnNurb.formInV();
  629.  
  630.     ASSERT(kFormInU    == MFnNurbsSurface::kOpen || kFormInU == MFnNurbsSurface::kClosed,
  631.                 "Invalid form in U");
  632.  
  633.     ASSERT(kFormInV == MFnNurbsSurface::kOpen || kFormInV == MFnNurbsSurface::kClosed,
  634.                 "Invalid form in V");
  635.  
  636.     // ensure that surface is a quad mesh
  637.     int    cCVsInU    = fnNurb.numCVsInU();
  638.     int    cCVsInV    = fnNurb.numCVsInV();
  639.  
  640.     ASSERT((cCVsInU - 1) % 3 == 0 && (cCVsInV - 1) % 3 == 0,
  641.                 "Invalid CV count");
  642.  
  643.     // ensure that there is at least one patch
  644.     int    cSpansInU    = (cCVsInU - 1) / 3;
  645.     int    cSpansInV    = (cCVsInV - 1) / 3;
  646.  
  647.     ASSERT(cSpansInU > 0 && cSpansInV > 0, 
  648.                 "Invalid span count");
  649.  
  650.  
  651.     // control vertices
  652.  
  653.     MPointArray rgCVs;
  654.  
  655.     fnNurb.getCVs(rgCVs);
  656.  
  657.     cVertices    = (int)rgCVs.length();
  658.     rgVertices    = new DtVec3f[cVertices];
  659.  
  660.     ASSERT(rgVertices, 
  661.                 "Can't allocate memory for vertex array");
  662.  
  663.     for (int iVertex = 0; iVertex < cVertices; iVertex++) 
  664.     {
  665.         rgVertices[iVertex].vec[0]    = (float)rgCVs[iVertex][0];
  666.         rgVertices[iVertex].vec[1]    = (float)rgCVs[iVertex][1];
  667.         rgVertices[iVertex].vec[2]    = (float)rgCVs[iVertex][2];
  668.     }
  669.  
  670.  
  671.  
  672.     // texture coordinates
  673.     cTexCoords    = (int)rgCVs.length();
  674.     rgTexCoords    = new DtVec2f[cTexCoords];
  675.  
  676.     ASSERT(rgTexCoords, 
  677.                 "Can't allocate memory for texture coordinate array");
  678.  
  679.     for (int iCVInU = 0, iTexCoord = 0; iCVInU < cCVsInU; iCVInU++)
  680.     {
  681.         for (int iCVInV = 0; iCVInV < cCVsInV; iCVInV++, iTexCoord++)
  682.         {
  683.             rgTexCoords[iTexCoord].vec[0] =  ((float)iCVInU) / ((float)(cCVsInU - 1));
  684.             rgTexCoords[iTexCoord].vec[1] =  ((float)iCVInV) / ((float)(cCVsInV - 1));
  685.         }
  686.     }
  687.  
  688.  
  689.  
  690.     // face info
  691.     cFaces    = cSpansInU * cSpansInV;
  692.     rgFaces    = new Face[cFaces];
  693.  
  694.     ASSERT(rgFaces, 
  695.                 "Can't allocate memory for patch array");
  696.  
  697.  
  698.     cFaceIndices    = 0;
  699.             
  700.     for (int iSpanInU = 0, iPatch = 0; iSpanInU < cSpansInU; iSpanInU++) 
  701.     {
  702.         int iCVIndexInU    = iSpanInU * 3;
  703.  
  704.         for (int iSpanInV = 0; iSpanInV < cSpansInV; iSpanInV++, iPatch++) 
  705.         {
  706.             int iCVIndexInV    = iSpanInV * 3;
  707.  
  708.             rgFaces[iPatch].m_cIndices        = 16;
  709.             rgFaces[iPatch].m_rgIndices        = new int[rgFaces[iPatch].m_cIndices];
  710.  
  711.             ASSERT(rgFaces[iPatch].m_rgIndices,
  712.                         "Could not allocate memory for patch indices");
  713.  
  714.             rgFaces[iPatch].m_rgIndices[0]    = cCVsInV * (iCVIndexInU + 0) + (iCVIndexInV + 0);
  715.             rgFaces[iPatch].m_rgIndices[1]    = cCVsInV * (iCVIndexInU + 1) + (iCVIndexInV + 0);
  716.             rgFaces[iPatch].m_rgIndices[2]    = cCVsInV * (iCVIndexInU + 2) + (iCVIndexInV + 0);
  717.  
  718.             rgFaces[iPatch].m_rgIndices[3]    = cCVsInV * (iCVIndexInU + 3) + (iCVIndexInV + 0);
  719.             rgFaces[iPatch].m_rgIndices[4]    = cCVsInV * (iCVIndexInU + 3) + (iCVIndexInV + 1);
  720.             rgFaces[iPatch].m_rgIndices[5]    = cCVsInV * (iCVIndexInU + 3) + (iCVIndexInV + 2);
  721.  
  722.             rgFaces[iPatch].m_rgIndices[6]    = cCVsInV * (iCVIndexInU + 3) + (iCVIndexInV + 3);
  723.             rgFaces[iPatch].m_rgIndices[7]    = cCVsInV * (iCVIndexInU + 2) + (iCVIndexInV + 3);
  724.             rgFaces[iPatch].m_rgIndices[8]    = cCVsInV * (iCVIndexInU + 1) + (iCVIndexInV + 3);
  725.  
  726.             rgFaces[iPatch].m_rgIndices[9]    = cCVsInV * (iCVIndexInU + 0) + (iCVIndexInV + 3);
  727.             rgFaces[iPatch].m_rgIndices[10]    = cCVsInV * (iCVIndexInU + 0) + (iCVIndexInV + 2);
  728.             rgFaces[iPatch].m_rgIndices[11]    = cCVsInV * (iCVIndexInU + 0) + (iCVIndexInV + 1);
  729.  
  730.             rgFaces[iPatch].m_rgIndices[12]    = cCVsInV * (iCVIndexInU + 1) + (iCVIndexInV + 1);
  731.             rgFaces[iPatch].m_rgIndices[13]    = cCVsInV * (iCVIndexInU + 2) + (iCVIndexInV + 1);
  732.  
  733.             rgFaces[iPatch].m_rgIndices[14]    = cCVsInV * (iCVIndexInU + 2) + (iCVIndexInV + 2);
  734.             rgFaces[iPatch].m_rgIndices[15]    = cCVsInV * (iCVIndexInU + 1) + (iCVIndexInV + 2);
  735.  
  736.             rgFaces[iPatch].m_iGroup        = 0;            //    WARNING: assumes only 1 material per surface
  737.  
  738.  
  739.             cFaceIndices    += rgFaces[iPatch].m_cIndices;
  740.         }
  741.     }
  742.  
  743.  
  744.  
  745.     // material info
  746.  
  747.     cGroups        = DtGroupGetCount(iShape);
  748.     rgGroups    = new Group[cGroups];
  749.  
  750.     ASSERT(rgGroups, 
  751.                 "Can't allocate memory for material group array");
  752.  
  753.  
  754.     ASSERT(cGroups == 1,
  755.                 "Assumption was made that NURBS surfaces have only 1 material");
  756.  
  757.  
  758.     for (int iGroup    = 0; iGroup < cGroups; iGroup++)
  759.     {
  760.  
  761.         // material name
  762.         DT_ATTEMPT(DtMtlGetName(iShape, iGroup, &rgGroups[iGroup].m_szMaterial));
  763.  
  764.         // texture file name
  765.         DT_ATTEMPT(MyDtTextureGetFileName(rgGroups[iGroup].m_szMaterial, &rgGroups[iGroup].m_szTextureFile));
  766.  
  767.         // diffuse color 
  768.         if (!rgGroups[iGroup].m_szTextureFile)
  769.         {
  770.             DT_ATTEMPT(DtMtlGetDiffuseClr(rgGroups[iGroup].m_szMaterial, 0, 
  771.                                        &rgGroups[iGroup].m_fDiffuseRed, 
  772.                                        &rgGroups[iGroup].m_fDiffuseGreen,
  773.                                        &rgGroups[iGroup].m_fDiffuseBlue));
  774.         }
  775.         else     // material has a texture
  776.         {
  777.             //    load the diffuse factor into the diffuse components
  778.  
  779.             int        iMaterial;
  780.  
  781.             DT_ATTEMPT(DtMtlGetID(iShape, iGroup, &iMaterial));
  782.  
  783.             MObject    mShader;
  784.  
  785.             DT_ATTEMPT(DtExt_MtlGetShader(iMaterial, mShader));
  786.  
  787.             MFnLambertShader    fnShader;
  788.  
  789.             fnShader.setObject(mShader);
  790.  
  791.             float    fDiffuseFactor    = fnShader.diffuseCoeff();
  792.  
  793.             rgGroups[iGroup].m_fDiffuseRed    = fDiffuseFactor;
  794.             rgGroups[iGroup].m_fDiffuseGreen    = fDiffuseFactor;
  795.             rgGroups[iGroup].m_fDiffuseBlue    = fDiffuseFactor;
  796.         }
  797.  
  798.         // specular color
  799.         DT_ATTEMPT(DtMtlGetSpecularClr(rgGroups[iGroup].m_szMaterial, 0, 
  800.                                     &rgGroups[iGroup].m_fSpecularRed, 
  801.                                     &rgGroups[iGroup].m_fSpecularGreen, 
  802.                                     &rgGroups[iGroup].m_fSpecularBlue));
  803.  
  804.         // emissive color
  805.         DT_ATTEMPT(DtMtlGetEmissiveClr(rgGroups[iGroup].m_szMaterial, 0, 
  806.                                     &rgGroups[iGroup].m_fEmissiveRed, 
  807.                                     &rgGroups[iGroup].m_fEmissiveGreen, 
  808.                                     &rgGroups[iGroup].m_fEmissiveBlue));
  809.  
  810.         // power / shininess
  811.         DT_ATTEMPT(DtMtlGetShininess(rgGroups[iGroup].m_szMaterial, 0, &rgGroups[iGroup].m_fShininess));
  812.  
  813.         // transparency / alpha
  814.         DT_ATTEMPT(DtMtlGetTransparency(rgGroups[iGroup].m_szMaterial, 0, &rgGroups[iGroup].m_fTransparency));
  815.     }
  816.     
  817.  
  818.  
  819.  
  820.  
  821.     // vertex duplication info (very simple for patch meshes)
  822.  
  823.     cReps    = (int)rgCVs.length();
  824.     rgReps    = new Rep[cReps];
  825.  
  826.     ASSERT(rgReps, 
  827.                 "Can't allocate memory for rep array");
  828.  
  829.     for (int iRep = 0; iRep < cReps; iRep++) 
  830.     {
  831.         rgReps[iRep].m_iNormalIdx    = -1;            // patches don't export normal info
  832.         rgReps[iRep].m_iTexCoordIdx    = iRep;
  833.         rgReps[iRep].m_iFirst        = iRep;
  834.         rgReps[iRep].m_iNext        = iRep;
  835.  
  836.         rgReps[iRep].m_cReps        = 1;
  837.     }
  838.  
  839.  
  840.  
  841.     // skinning info
  842.             
  843.  
  844.     MObject    objShape;
  845.     MObject objTransform;
  846.     MObject    objInput;
  847.  
  848.     DT_ATTEMPT(DtExt_ShapeGetShapeNode(iShape, objShape));
  849.     DT_ATTEMPT(DtExt_ShapeGetTransform(iShape, objTransform));
  850.  
  851.  
  852.  
  853.  
  854.     // load the mesh's world transform (needed if skinning info is found)
  855.     MDagPath    pathTransform;
  856.  
  857.     MFnDagNode(objTransform).getPath(pathTransform);
  858.  
  859.     MMatrix        matMeshWorldTransform    = pathTransform.inclusiveMatrix();
  860.  
  861.  
  862.  
  863.  
  864.  
  865.     cBones                = 0;
  866.     rgBones                = NULL;
  867.  
  868.     cMaxBonesPerVertex    = 0;
  869.     cMaxBonesPerFace    = 0;
  870.  
  871.  
  872.     MObjectArray    rgobjBones;
  873.  
  874.  
  875.  
  876.  
  877.  
  878.  
  879.  
  880.     // smooth skinning
  881.  
  882.     bool*    rgbNonZeroFlagTable    = NULL;        // table of influences vs. vertices
  883.     int*    rgcNonZeros            = NULL;        // array of influence counts 
  884.  
  885.     bool bFoundSmoothSkin    = false;
  886.  
  887.     if (objShape.hasFn(MFn::kNurbsSurface))         // if this shape is a mesh
  888.     { 
  889.         // loop through skin clusters
  890.         for (MItDependencyNodes itSkin(MFn::kSkinClusterFilter); !itSkin.isDone(); itSkin.next()) 
  891.         {
  892.             MFnSkinCluster fnSkin(itSkin.item());
  893.  
  894.             // load input and output geometries
  895.             MObjectArray    rgInputs;
  896.             MObjectArray    rgOutputs;
  897.  
  898.             fnSkin.getInputGeometry(rgInputs);
  899.             fnSkin.getOutputGeometry(rgOutputs);
  900.  
  901.             assert(rgInputs.length() == rgOutputs.length());        // ensure that input geometry count 
  902.                                                                     // equals output geometry count
  903.  
  904.             int    cInputs, cOutputs;
  905.  
  906.             cInputs    = cOutputs    = (int)rgOutputs.length();
  907.  
  908.             // loop through the output geometries
  909.             for (int iOutput = 0, iInput = 0; iOutput < cOutputs; iOutput++, iInput++) 
  910.             {
  911.                 assert(iOutput == iInput);        // sanity check
  912.  
  913.                 
  914.                 if (rgOutputs[iOutput] == objShape)         // if our shape is one of the output geometries
  915.                 {
  916.                     MDagPathArray    rgdagpathInfluences;
  917.                     
  918.                     cBones    = (int)fnSkin.influenceObjects(rgdagpathInfluences, &mStat);
  919.  
  920.                     rgBones    = new Bone[cBones];
  921.  
  922.                     ASSERT(rgBones,
  923.                                 "Could not allocate memory for bone array");
  924.  
  925.  
  926.                     // initialize bones
  927.                     for (int iBone = 0; iBone < cBones; iBone++) 
  928.                     {    // WARNING: not checking for new failure
  929.                         rgBones[iBone].m_szName            = new char[256];
  930.                         rgBones[iBone].m_cReps            = 0;
  931.                         rgBones[iBone].m_cWeights        = 0;
  932.                         rgBones[iBone].m_rgiVertices    = new int[cVertices];
  933.                         rgBones[iBone].m_rgfWeights        = new float[cVertices];
  934.  
  935.                         g_Strings.add(rgBones[iBone].m_szName);        // housekeeping
  936.  
  937.                         // bone name
  938.                         strcpy(rgBones[iBone].m_szName, rgdagpathInfluences[iBone].partialPathName().asChar());
  939.  
  940.                         // matrix offset
  941.                         MFnIkJoint fnBone(rgdagpathInfluences[iBone]);
  942.  
  943.                         MObject objBindPose;
  944.  
  945.                         fnBone.findPlug("bindPose").getValue(objBindPose);
  946.  
  947.                         MFnMatrixData fnBindPose(objBindPose);
  948.  
  949.                         (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iBone].m_matOffset);
  950.  
  951.  
  952.  
  953.                         rgobjBones.append(rgdagpathInfluences[iBone].node());
  954.                     }
  955.  
  956.                     rgcNonZeros            = new int[cVertices];
  957.  
  958.                     ASSERT(rgcNonZeros,
  959.                                 "Could not allocate memory for non zero count array");
  960.  
  961.                     rgbNonZeroFlagTable    = new bool[cVertices * cBones];
  962.  
  963.                     ASSERT(rgbNonZeroFlagTable,
  964.                                 "Could not allocate memory for non zero table");
  965.  
  966.                     // bone info; calculate max number of bones per vertex
  967.                     cMaxBonesPerVertex = 0;
  968.  
  969.                     int iVertex = 0;
  970.  
  971.                     MFnNurbsSurface fnOutput(rgOutputs[iOutput]);
  972.  
  973.                     MDagPath dagpathOutputShape;
  974.                 
  975.                     fnOutput.getPath(dagpathOutputShape);
  976.  
  977.                     // loop through the vertices
  978.                     for (MItGeometry itGeom(rgOutputs[iOutput]); !itGeom.isDone(); itGeom.next()) 
  979.                     {
  980.     
  981.                         MFloatArray rgfWeights;
  982.  
  983.                         unsigned cInfs;
  984.  
  985.                         fnSkin.getWeights(dagpathOutputShape, itGeom.component(), rgfWeights, cInfs);
  986.  
  987.                         int a = rgdagpathInfluences.length();
  988.                         int b = rgfWeights.length();
  989.                         int c = itGeom.count();
  990.  
  991.                         assert(rgdagpathInfluences.length() == rgfWeights.length());
  992.                         assert(rgfWeights.length() == cInfs);
  993.  
  994.                         rgcNonZeros[iVertex] = 0;
  995.  
  996.  
  997.                         float fWeightSum = 0.0f;
  998.  
  999.                         for (int iBone = 0; iBone < cBones; iBone++)
  1000.                             fWeightSum += rgfWeights[iBone];
  1001.  
  1002.                         assert(fWeightSum > 0.00001f);
  1003.  
  1004.                         for (iBone = 0; iBone < cBones; iBone++) 
  1005.                         {
  1006.                             rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = false;
  1007.  
  1008.                             rgfWeights[iBone] = rgfWeights[iBone] / fWeightSum;        // normalize the weight
  1009.  
  1010.                             if (rgfWeights[iBone] != 0.0f) 
  1011.                             {
  1012.                                 rgcNonZeros[iVertex]++;
  1013.  
  1014.                                 rgBones[iBone].m_cReps += rgReps[iVertex].m_cReps;
  1015.         
  1016.                                 rgBones[iBone].m_rgiVertices[rgBones[iBone].m_cWeights]    = iVertex;                            
  1017.                                 rgBones[iBone].m_rgfWeights[rgBones[iBone].m_cWeights]    = rgfWeights[iBone];
  1018.  
  1019.                                 rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = true;
  1020.  
  1021.                                 rgBones[iBone].m_cWeights++;
  1022.                             }
  1023.                         }
  1024.  
  1025.  
  1026.                         if (rgcNonZeros[iVertex] > cMaxBonesPerVertex)
  1027.                             cMaxBonesPerVertex = rgcNonZeros[iVertex];
  1028.  
  1029.                         iVertex++;
  1030.                     }
  1031.  
  1032.  
  1033.  
  1034.                     // calculate max number of bones per vertex
  1035.  
  1036.                     cMaxBonesPerFace    = 0;
  1037.  
  1038.                     for (int iFace = 0; iFace < cFaces; iFace++) 
  1039.                     {
  1040.                         int    cBonesPerFace    = 0;
  1041.  
  1042.                         for (int iBone = 0; iBone < cBones; iBone++) 
  1043.                         {
  1044.                             for (int iIndex = 0; iIndex < rgFaces[iFace].m_cIndices; iIndex++) 
  1045.                             {
  1046.                                 if (rgbNonZeroFlagTable[iBone * cVertices + rgReps[rgFaces[iFace].m_rgIndices[iIndex]].m_iFirst]) 
  1047.                                 {
  1048.                                     cBonesPerFace++;
  1049.  
  1050.                                     break;
  1051.                                 }
  1052.                             }
  1053.                         }
  1054.  
  1055.                         if (cBonesPerFace > cMaxBonesPerFace)
  1056.                             cMaxBonesPerFace = cBonesPerFace;
  1057.                     }
  1058.  
  1059.  
  1060.  
  1061.  
  1062.                     objInput = rgInputs[iInput];
  1063.  
  1064.                     bFoundSmoothSkin = true;
  1065.  
  1066.                     break;
  1067.                 }
  1068.             }
  1069.  
  1070.             if (bFoundSmoothSkin)
  1071.                 break;
  1072.         }
  1073.     }
  1074.  
  1075.  
  1076.     delete[] rgcNonZeros;
  1077.     delete[] rgbNonZeroFlagTable;
  1078.  
  1079.  
  1080.  
  1081.  
  1082.  
  1083.  
  1084.  
  1085.  
  1086.  
  1087.  
  1088.  
  1089.  
  1090.  
  1091.  
  1092.  
  1093.  
  1094.  
  1095.  
  1096.  
  1097.     // rigid skinning
  1098.  
  1099.     rgbNonZeroFlagTable    = NULL;
  1100.  
  1101.     bool    bFoundRigidSkin    = false;
  1102.  
  1103.     if (!bFoundSmoothSkin)     
  1104.     {
  1105.         cBones            = 1;                        // zero'th bone is the extra "fake" bone
  1106.         int cBonesMax    = 64;
  1107.         rgBones            = new Bone[cBonesMax];
  1108.  
  1109.         ASSERT(rgBones,
  1110.                     "Could not allocate memory for bone array");
  1111.  
  1112.         rgbNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  1113.  
  1114.         ASSERT(rgbNonZeroFlagTable,
  1115.                     "Could not allocate memory for non-zero flag table");
  1116.  
  1117.         // fill non zero table with 0's
  1118.         memset(rgbNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  1119.  
  1120.         // initialize "fake" iBone
  1121.         // WARNING: not checking for new failure
  1122.         rgBones[0].m_szName            = new char[256];
  1123.         rgBones[0].m_cReps            = 0;
  1124.         rgBones[0].m_cWeights        = 0;
  1125.         rgBones[0].m_rgfWeights        = new float[cVertices];
  1126.         rgBones[0].m_rgiVertices    = new int[cVertices];
  1127.  
  1128.         g_Strings.add(rgBones[0].m_szName);                            // housekeeping
  1129.  
  1130.         strcpy(rgBones[0].m_szName, SCENE_ROOT);                    // bone name
  1131.     
  1132.         matMeshWorldTransform.get(rgBones[0].m_matOffset);            // "fake" bone has identity matrix
  1133.  
  1134.  
  1135.         // loop through joint clusters
  1136.         for (MItDependencyNodes itCluster(MFn::kJointCluster); !itCluster.isDone(); itCluster.next()) 
  1137.         {
  1138.             MFnWeightGeometryFilter fnCluster(itCluster.item());
  1139.  
  1140.             // load input and output geometries
  1141.             MObjectArray    rgInputs;
  1142.             MObjectArray    rgOutputs;
  1143.  
  1144.             fnCluster.getInputGeometry(rgInputs);
  1145.             fnCluster.getOutputGeometry(rgOutputs);
  1146.  
  1147.             assert(rgInputs.length() == rgOutputs.length());    // ensure input geometry count equals 
  1148.                                                                 // output geometry count
  1149.  
  1150.             int    cInputs, cOutputs;
  1151.  
  1152.             cInputs    = cOutputs    
  1153.                 = (int)rgOutputs.length();
  1154.  
  1155.             // loop through the output geometries
  1156.             for (int iOutput = 0, iInput = 0; iOutput < cOutputs; iOutput++, iInput++) 
  1157.             {
  1158.                 assert(iOutput == iInput);
  1159.                 
  1160.                 if (rgOutputs[iOutput] == objShape)     // our shape is one of the output geometries
  1161.                 {
  1162.                     bFoundRigidSkin    = true;
  1163.         
  1164.                     assert(rgInputs[iInput] == fnCluster.inputShapeAtIndex(iInput));    // sanity check
  1165.  
  1166.                     objInput    = rgInputs[iInput];
  1167.  
  1168.                     // get bone
  1169.                     MPlug        plgMatrix    = fnCluster.findPlug("matrix", &mStat);
  1170.  
  1171.                     MPlugArray    rgplgMatrixConnections;
  1172.  
  1173.                     plgMatrix.connectedTo(rgplgMatrixConnections, true, false);            // get source plugs
  1174.                     assert(rgplgMatrixConnections.length() == 1);
  1175.  
  1176.                     MObject    objBone    = rgplgMatrixConnections[0].node();
  1177.  
  1178.                     assert(objBone.hasFn(MFn::kJoint));
  1179.  
  1180.                     MFnIkJoint fnBone(objBone);
  1181.  
  1182.                     char    szBone[64];
  1183.  
  1184.                     strcpy(szBone, fnBone.name().asChar());
  1185.  
  1186.                     // find bone's index in current bone list
  1187.                     for (int iBone = 1; iBone < cBones;    iBone++) 
  1188.                     {
  1189.                         if (!strcmp(rgBones[iBone].m_szName, szBone))
  1190.                             break;
  1191.                     }
  1192.     
  1193.                     if (iBone == cBones)     // bone was not found in current bone list
  1194.                     {
  1195.                         // add bone
  1196.                         if (cBones >= cBonesMax) 
  1197.                         {
  1198.                             // double array size
  1199.                             cBonesMax  += cBonesMax;
  1200.  
  1201.                             Bone*    rgNewBones    = new Bone[cBonesMax];
  1202.  
  1203.                             ASSERT(rgNewBones, 
  1204.                                         "Could not allocate memory for new bone array");
  1205.  
  1206.                             memcpy(rgNewBones, rgBones, cBones * sizeof(Bone));
  1207.  
  1208.                             delete[] rgBones;
  1209.  
  1210.                             rgBones    = rgNewBones;
  1211.  
  1212.  
  1213.                             bool*    rgbNewNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  1214.  
  1215.                             ASSERT(rgbNewNonZeroFlagTable, 
  1216.                                         "Could not allocate memory for new non-zero flag table");
  1217.  
  1218.                             memset(rgbNewNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  1219.                             memcpy(rgbNewNonZeroFlagTable, rgbNonZeroFlagTable, cBones * cVertices * sizeof(bool));
  1220.  
  1221.                             delete[] rgbNonZeroFlagTable;
  1222.  
  1223.                             rgbNonZeroFlagTable    = rgbNewNonZeroFlagTable;
  1224.                         }
  1225.         
  1226.                         // initialize iBone
  1227.                         // WARNING: not checking for new failure
  1228.                         rgBones[iBone].m_szName            = new char[256];
  1229.                         rgBones[iBone].m_cReps            = 0;
  1230.                         rgBones[iBone].m_cWeights        = 0;
  1231.                         rgBones[iBone].m_rgiVertices    = new int[cVertices];
  1232.                         rgBones[iBone].m_rgfWeights        = new float[cVertices];
  1233.  
  1234.                         g_Strings.add(rgBones[iBone].m_szName);                            // housekeeping
  1235.  
  1236.                         strcpy(rgBones[iBone].m_szName, szBone);                        // bone name
  1237.     
  1238.                         // matrix info
  1239.                         MObject objBindPose;
  1240.  
  1241.                         fnBone.findPlug("bindPose").getValue(objBindPose);
  1242.  
  1243.                         MFnMatrixData fnBindPose(objBindPose);
  1244.  
  1245.                         (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iBone].m_matOffset);
  1246.  
  1247.  
  1248.                         rgobjBones.append(objBone);
  1249.  
  1250.                         cBones++;
  1251.                     }
  1252.  
  1253.  
  1254.  
  1255.                     char    szParent[64];
  1256.  
  1257.                     bool    bFoundParent    = false;
  1258.                     MObject    objParent; 
  1259.  
  1260.                     for (int iParent = 0; iParent < (int)fnBone.parentCount(); iParent++) 
  1261.                     {
  1262.                         objParent    = fnBone.parent(iParent);
  1263.  
  1264.                         MFnDagNode    fnParent(objParent);
  1265.                         
  1266.                         strcpy(szParent, fnParent.name().asChar());        // parent's name
  1267.  
  1268.                         for (int iShape_ = 0; iShape_ < DtShapeGetCount(); iShape_++) 
  1269.                         {
  1270.                             char*    szShape;
  1271.  
  1272.                             DT_ATTEMPT(DtShapeGetName(iShape_, &szShape));
  1273.  
  1274.                             if (!strcmp(szParent, szShape)) 
  1275.                             {
  1276.                                 bFoundParent    = true;
  1277.  
  1278.                                 break;
  1279.                             }
  1280.                         }
  1281.  
  1282.                         if (bFoundParent)
  1283.                             break;
  1284.                     }
  1285.   
  1286.                     iParent    = 0;
  1287.  
  1288.                     if (bFoundParent)     // parent shape found
  1289.                     {
  1290.                         // find parent bone's index in current bone list
  1291.                         for (iParent = 1; iParent < cBones;    iParent++) 
  1292.                         {
  1293.                             if (!strcmp(rgBones[iParent].m_szName, szParent)) 
  1294.                             {
  1295.                                 break;
  1296.                             }
  1297.                         }
  1298.  
  1299.  
  1300.                         if (iParent == cBones)         // parent bone was not found in current bone list
  1301.                         {
  1302.                             // add parent bone
  1303.                             if (cBones >= cBonesMax) 
  1304.                             {
  1305.                                 // double array size
  1306.                                 cBonesMax  += cBonesMax;
  1307.  
  1308.                                 Bone*    rgNewBones    = new Bone[cBonesMax];
  1309.  
  1310.                                 ASSERT(rgNewBones, 
  1311.                                             "Could not allocate memory for new bone array");
  1312.     
  1313.                                 memcpy(rgNewBones, rgBones, cBones * sizeof(Bone));
  1314.     
  1315.                                 delete[] rgBones;
  1316.  
  1317.                                 rgBones    = rgNewBones;
  1318.  
  1319.                                 
  1320.                                 bool*    rgbNewNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  1321.  
  1322.                                 ASSERT(rgbNewNonZeroFlagTable, 
  1323.                                             "Could not allocate memory for new non-zero flag table");
  1324.  
  1325.                                 memset(rgbNewNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  1326.                                 memcpy(rgbNewNonZeroFlagTable, rgbNonZeroFlagTable, cBones * cVertices * sizeof(bool));
  1327.  
  1328.                                 delete[] rgbNonZeroFlagTable;
  1329.  
  1330.                                 rgbNonZeroFlagTable    = rgbNewNonZeroFlagTable;
  1331.                             }
  1332.             
  1333.                             // initialize iBone
  1334.                             // WARNING: not checking for new failure
  1335.                             rgBones[iParent].m_szName        = new char[256];
  1336.                             rgBones[iParent].m_cReps        = 0;
  1337.                             rgBones[iParent].m_cWeights        = 0;
  1338.                             rgBones[iParent].m_rgiVertices    = new int[cVertices];
  1339.                             rgBones[iParent].m_rgfWeights    = new float[cVertices];
  1340.     
  1341.                             g_Strings.add(rgBones[iParent].m_szName);            // housekeeping
  1342.     
  1343.                             strcpy(rgBones[iParent].m_szName, szParent);        // bone name
  1344.  
  1345.                             // matrix info
  1346.                             MObject    objBindPose;
  1347.     
  1348.                             assert(objParent.hasFn(MFn::kJoint));
  1349.  
  1350.                             MFnIkJoint(objParent).findPlug("bindPose").getValue(objBindPose);
  1351.     
  1352.                             MFnMatrixData fnBindPose(objBindPose);
  1353.     
  1354.                             (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iParent].m_matOffset);
  1355.  
  1356.  
  1357.                             rgobjBones.append(objParent);
  1358.  
  1359.                             cBones++;
  1360.                         }
  1361.                     }
  1362.  
  1363.  
  1364.                     // load weights
  1365.                     MPlug        plgMessage    = fnCluster.findPlug("message");
  1366.  
  1367.                     MPlugArray    rgplgMessageConnections;
  1368.  
  1369.                     plgMessage.connectedTo(rgplgMessageConnections, false, true);    // get destination plugs
  1370.  
  1371.                     assert(rgplgMessageConnections.length() == 1);
  1372.                     assert(rgplgMessageConnections[0].node().hasFn(MFn::kSet));
  1373.  
  1374.                     MFnSet fnSet(rgplgMessageConnections[0].node());
  1375.                 
  1376.                     MSelectionList list;
  1377.  
  1378.                     fnSet.getMembers(list, false);
  1379.  
  1380.                     assert(list.length() == 1);
  1381.  
  1382.                     MDagPath    path;
  1383.                     MObject        objComponents;
  1384.  
  1385.                     list.getDagPath(0, path, objComponents);
  1386.  
  1387.                     MFloatArray    rgWeights;
  1388.  
  1389.                     fnCluster.getWeights(path, objComponents, rgWeights);
  1390.  
  1391.                     assert(objComponents.hasFn(MFn::kDoubleIndexedComponent));
  1392.  
  1393.  
  1394.                     MFnDoubleIndexedComponent fnComponent(objComponents);
  1395.  
  1396.                     assert(fnComponent.elementCount() == (int)rgWeights.length());
  1397.  
  1398.                     // loop through the weights
  1399.                     for (int iWeight = 0; iWeight < (int)rgWeights.length(); iWeight++) 
  1400.                     {
  1401.                         assert(rgWeights[iWeight] <= 1.0f);
  1402.  
  1403.                         int    iU, iV;
  1404.  
  1405.                         fnComponent.getElement(iWeight, iU, iV);
  1406.  
  1407.                         // WARNING: check calculation of iVertex
  1408.                         int    iVertex    = iU * cCVsInV + iV;
  1409.                         
  1410.                         rgBones[iBone].m_rgfWeights[rgBones[iBone].m_cWeights]    = rgWeights[iWeight];
  1411.                         rgBones[iBone].m_rgiVertices[rgBones[iBone].m_cWeights]    = iVertex;
  1412.  
  1413.                         rgBones[iBone].m_cReps     += rgReps[iVertex].m_cReps;
  1414.                         rgBones[iBone].m_cWeights++;
  1415.  
  1416.                         rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = true;
  1417.  
  1418.                         if (rgWeights[iWeight] != 1.0f) 
  1419.                         {
  1420.                             rgBones[iParent].m_rgfWeights[rgBones[iParent].m_cWeights]    = 1.0f - rgWeights[iWeight];
  1421.                             rgBones[iParent].m_rgiVertices[rgBones[iParent].m_cWeights]    = iVertex;
  1422.  
  1423.                             rgBones[iParent].m_cReps   += rgReps[iVertex].m_cReps;
  1424.                             rgBones[iParent].m_cWeights++;                // IMPORTANT: Don't change line position
  1425.  
  1426.                             rgbNonZeroFlagTable[iParent * cVertices + iVertex]    = true;
  1427.                         }
  1428.                     }
  1429.  
  1430.                     break;
  1431.                 }    // if found our mesh
  1432.             }    // loop thru geom's
  1433.         }    // loop thru joint clusters
  1434.  
  1435.  
  1436.         if (cBones == 1)         // no rigid skinning found
  1437.         {
  1438.             delete[] rgBones[0].m_rgfWeights;
  1439.             delete[] rgBones[0].m_rgiVertices;
  1440.  
  1441.             cBones    = 0;
  1442.         }
  1443.         else 
  1444.         {
  1445.             // at most 2 bones per vertex in rigid skinning (i.e. bone + parent)
  1446.             cMaxBonesPerVertex    = 2;
  1447.  
  1448.             // calculate max number of bones per vertex
  1449.             cMaxBonesPerFace    = 0;
  1450.  
  1451.             for (int iFace = 0; iFace < cFaces; iFace++) 
  1452.             {
  1453.                 int    cBonesPerFace    = 0;
  1454.  
  1455.                 for (int iBone = 0; iBone < cBones; iBone++) 
  1456.                 {
  1457.                     for (int iIndex = 0; iIndex < rgFaces[iFace].m_cIndices; iIndex++) 
  1458.                     {
  1459.                         if (rgbNonZeroFlagTable[iBone * cVertices + rgReps[rgFaces[iFace].m_rgIndices[iIndex]].m_iFirst]) 
  1460.                         {
  1461.                             cBonesPerFace++;
  1462.  
  1463.                             break;
  1464.                         }
  1465.                     }
  1466.                 }
  1467.  
  1468.                 if (cBonesPerFace > cMaxBonesPerFace)
  1469.                     cMaxBonesPerFace = cBonesPerFace;
  1470.             }
  1471.             
  1472.         }
  1473.     }
  1474.                 
  1475.                 
  1476.     delete[] rgbNonZeroFlagTable;
  1477.  
  1478.  
  1479.  
  1480.  
  1481.  
  1482.  
  1483.  
  1484.  
  1485.  
  1486.  
  1487.  
  1488.  
  1489.  
  1490.  
  1491.  
  1492.  
  1493.  
  1494.  
  1495.  
  1496.     // reload control vertices if skinning info was found
  1497.  
  1498.     if (bFoundSmoothSkin || bFoundRigidSkin)
  1499.     {
  1500.         delete[]    rgVertices;
  1501.  
  1502.         MyDtShapeGetControlPoints(objInput, objShape, &cVertices, &rgVertices);
  1503.     }
  1504.  
  1505.  
  1506.  
  1507.  
  1508.  
  1509.     // mesh type
  1510.     pShape->m_kType            = Mesh::PATCH_MESH;
  1511.  
  1512.  
  1513.     EXIT;
  1514.  
  1515.     return hr;    
  1516. }
  1517.  
  1518.  
  1519.  
  1520.  
  1521.  
  1522.  
  1523.  
  1524.  
  1525.  
  1526.  
  1527. HRESULT    LoadPolyMesh
  1528.         (
  1529.             int        iShape, 
  1530.             Mesh*    pShape
  1531.         ) 
  1532. {
  1533.     HRESULT    hr        = S_OK;
  1534.     MStatus    mStat    = MStatus::kSuccess;
  1535.  
  1536.  
  1537.     // set up references
  1538.  
  1539.     Mesh::ShapeType&    kType        = pShape->m_kType;
  1540.  
  1541.     int&        cReps                = pShape->m_cReps;
  1542.     Rep*&        rgReps                = pShape->m_rgReps;
  1543.  
  1544.     int&        cVertices            = pShape->m_cVertices;
  1545.     DtVec3f*&    rgVertices            = pShape->m_rgVertices;
  1546.  
  1547.     int&        cNormals            = pShape->m_cNormals;
  1548.     DtVec3f*&    rgNormals            = pShape->m_rgNormals;
  1549.  
  1550.     int&        cTexCoords            = pShape->m_cTexCoords;
  1551.     DtVec2f*&    rgTexCoords            = pShape->m_rgTexCoords;
  1552.  
  1553.     int&        cVertexColors        = pShape->m_cVertexColors;
  1554.     DtRGBA*&    rgVertexColors        = pShape->m_rgVertexColors;
  1555.  
  1556.  
  1557.     int&        cFaces                = pShape->m_cFaces;
  1558.     Face*&        rgFaces                = pShape->m_rgFaces;
  1559.  
  1560.     int&        cFaceIndices        = pShape->m_cFaceIndices;
  1561.  
  1562.     int&        cGroups                = pShape->m_cGroups;
  1563.     Group*&        rgGroups            = pShape->m_rgGroups;
  1564.  
  1565.  
  1566.     int&        cBones                = pShape->m_cBones;
  1567.     Bone*&        rgBones                = pShape->m_rgBones;
  1568.  
  1569.     int&        cMaxBonesPerVertex    = pShape->m_cMaxBonesPerVertex;
  1570.     int&        cMaxBonesPerFace    = pShape->m_cMaxBonesPerFace;
  1571.  
  1572.  
  1573.  
  1574.  
  1575.     INIT;
  1576.  
  1577.  
  1578.  
  1579.  
  1580.     cGroups        = DtGroupGetCount(iShape);
  1581.     rgGroups    = new Group[cGroups];
  1582.  
  1583.     ASSERT(rgGroups,
  1584.                 "Could not allocate memory for group array");
  1585.  
  1586.     DT_ATTEMPT(DtShapeGetVertices(iShape, &cVertices, &rgVertices));
  1587.  
  1588.     DT_ATTEMPT(DtShapeGetNormals(iShape, &cNormals, &rgNormals));
  1589.  
  1590.     DT_ATTEMPT(DtShapeGetTextureVertices(iShape, &cTexCoords, &rgTexCoords));
  1591.     
  1592.     DT_ATTEMPT(DtShapeGetVerticesColor(iShape, &cVertexColors, &rgVertexColors));    
  1593.     
  1594.     ASSERT(cVertexColors == cVertices,
  1595.                 "Vertex color count does not match vertex count");
  1596.  
  1597.  
  1598.     int    cRepsMax    = cReps    
  1599.                     = cVertices;
  1600.     rgReps            = new Rep[cRepsMax];
  1601.  
  1602.     ASSERT(rgReps,
  1603.                 "Could not allocate memory for rep array");
  1604.     
  1605.     // initialize reps
  1606.     for (int iRep = 0; iRep < cReps; iRep++) 
  1607.     {
  1608.         rgReps[iRep].m_iTexCoordIdx    = -1;                        // signifies "unvisited"
  1609.         rgReps[iRep].m_iNormalIdx    = -1;                        // signifies "unvisited"
  1610.         rgReps[iRep].m_iNext        = iRep;
  1611.         rgReps[iRep].m_iFirst        = iRep;
  1612.  
  1613.         rgReps[iRep].m_cReps        = 1;
  1614.     }
  1615.  
  1616.  
  1617.     int    cFacesMax    = cFaces
  1618.                     = 0;
  1619.     rgFaces            = new Face[cFacesMax];
  1620.  
  1621.     ASSERT(rgFaces,
  1622.                 "Could not allocate memory for face array");
  1623.  
  1624.     cFaceIndices    = 0;                // total number of indices over all faces
  1625.  
  1626.  
  1627.     // go through each group of polygons (grouped by material)
  1628.     for (int iGroup = 0; iGroup < cGroups; iGroup++) 
  1629.     {
  1630.         // material name
  1631.         DT_ATTEMPT(DtMtlGetName(iShape, iGroup, &rgGroups[iGroup].m_szMaterial));
  1632.  
  1633.         // texture file name
  1634.  
  1635.         DT_ATTEMPT(MyDtTextureGetFileName(rgGroups[iGroup].m_szMaterial, &rgGroups[iGroup].m_szTextureFile));
  1636.  
  1637.  
  1638.         // diffuse color 
  1639.         if (!rgGroups[iGroup].m_szTextureFile)
  1640.         {
  1641.             DT_ATTEMPT(DtMtlGetDiffuseClr(rgGroups[iGroup].m_szMaterial, 0, 
  1642.                                        &rgGroups[iGroup].m_fDiffuseRed, 
  1643.                                        &rgGroups[iGroup].m_fDiffuseGreen, 
  1644.                                        &rgGroups[iGroup].m_fDiffuseBlue));
  1645.         }
  1646.         else 
  1647.         {    // if the material has a texture then load the diffuse factor into the diffuse components
  1648.             int        iMaterial;
  1649.  
  1650.             DT_ATTEMPT(DtMtlGetID(iShape, iGroup, &iMaterial));
  1651.  
  1652.             MObject    objShader;
  1653.  
  1654.             DT_ATTEMPT(DtExt_MtlGetShader(iMaterial, objShader));
  1655.  
  1656.             MFnLambertShader    fnShader(objShader);
  1657.  
  1658.             float    fDiffuseFactor    = fnShader.diffuseCoeff();
  1659.  
  1660.             rgGroups[iGroup].m_fDiffuseRed        = fDiffuseFactor;
  1661.             rgGroups[iGroup].m_fDiffuseGreen    = fDiffuseFactor;
  1662.             rgGroups[iGroup].m_fDiffuseBlue        = fDiffuseFactor;
  1663.         }
  1664.  
  1665.         // specular color
  1666.         DT_ATTEMPT(DtMtlGetSpecularClr(rgGroups[iGroup].m_szMaterial, 0, 
  1667.                                         &rgGroups[iGroup].m_fSpecularRed, 
  1668.                                         &rgGroups[iGroup].m_fSpecularGreen, 
  1669.                                         &rgGroups[iGroup].m_fSpecularBlue));
  1670.  
  1671.         // emissive color
  1672.         DT_ATTEMPT(DtMtlGetEmissiveClr(rgGroups[iGroup].m_szMaterial, 0, 
  1673.                                         &rgGroups[iGroup].m_fEmissiveRed, 
  1674.                                         &rgGroups[iGroup].m_fEmissiveGreen, 
  1675.                                         &rgGroups[iGroup].m_fEmissiveBlue));
  1676.  
  1677.         // power / shininess
  1678.         DT_ATTEMPT(DtMtlGetShininess(rgGroups[iGroup].m_szMaterial, 0, &rgGroups[iGroup].m_fShininess));
  1679.  
  1680.         // transparency / alpha
  1681.         DT_ATTEMPT(DtMtlGetTransparency(rgGroups[iGroup].m_szMaterial, 0, &rgGroups[iGroup].m_fTransparency));
  1682.  
  1683.  
  1684.         int    cPolygons;
  1685.  
  1686.         DT_ATTEMPT(DtPolygonGetCount(iShape, iGroup, &cPolygons));
  1687.  
  1688.  
  1689.         // increase array size
  1690.         cFacesMax  += cPolygons;
  1691.  
  1692.         Face*    rgNewFaces    = new Face[cFacesMax];
  1693.         
  1694.         ASSERT(rgNewFaces,
  1695.                     "Could not allocate memory for new face array");
  1696.  
  1697.         memcpy(rgNewFaces, rgFaces, cFaces * sizeof(Face));
  1698.  
  1699.         delete[] rgFaces;
  1700.  
  1701.         rgFaces    = rgNewFaces;
  1702.  
  1703.         // loop through the polygons in this shape
  1704.         for (int iPolygon = 0; iPolygon < cPolygons; iPolygon++) 
  1705.         {
  1706.             int        cIndices;
  1707.  
  1708.             long*    rglVertexIndices;
  1709.             long*    rglNormalIndices;
  1710.             long*    rglTexCoordIndices;
  1711.  
  1712.             DT_ATTEMPT(DtPolygonGetIndices(iPolygon, &cIndices, &rglVertexIndices, &rglNormalIndices, &rglTexCoordIndices));
  1713.  
  1714.             cFaceIndices    +=    cIndices;
  1715.  
  1716.             // initialize face
  1717.             rgFaces[cFaces].m_cIndices    = cIndices;
  1718.             rgFaces[cFaces].m_rgIndices    = new int[cIndices];
  1719.  
  1720.             ASSERT(rgFaces[cFaces].m_rgIndices,
  1721.                         "Could not allocate memory for face indices array");
  1722.             
  1723.             rgFaces[cFaces].m_iGroup    = iGroup;
  1724.  
  1725.             // no need for the following 2 lines
  1726. ////        memcpy(rgFaces[cFaces].m_rgNormalIndices, rgNormalIndices, cIndices * sizeof(long));
  1727. //            memcpy(rgFaces[cFaces].m_rgIndices, rgVertexIndices, cIndices * sizeof(long));
  1728.  
  1729.             // create repetition if texture coords differ
  1730.             for (int iIndex = 0; iIndex < cIndices; iIndex++) 
  1731.             {
  1732.                 int iRep    = rglVertexIndices[iIndex];
  1733.                 int iLastRep;
  1734.  
  1735.                 bool bFound = false;
  1736.  
  1737.                 do 
  1738.                 {
  1739.                     if (rglTexCoordIndices[iIndex] == rgReps[iRep].m_iTexCoordIdx && rglNormalIndices[iIndex] == rgReps[iRep].m_iNormalIdx)
  1740.                         bFound = true;
  1741.  
  1742.                     iLastRep    = iRep;
  1743.                     iRep        = rgReps[iRep].m_iNext;
  1744.                 } while (!bFound && rgReps[iRep].m_iNext != rgReps[iRep].m_iFirst);
  1745.  
  1746.  
  1747.                 if (bFound) 
  1748.                 {
  1749.                     rgFaces[cFaces].m_rgIndices[iIndex]    = iLastRep;    // update face indices
  1750.                 }
  1751.                 else 
  1752.                 {
  1753.                     if (rgReps[rgReps[iRep].m_iFirst].m_iTexCoordIdx == -1)     // if first time through this rep
  1754.                     {
  1755.                         // initialize index into lump of texture coordinates
  1756.                         rgReps[rgReps[iRep].m_iFirst].m_iTexCoordIdx    = rglTexCoordIndices[iIndex];
  1757.                         rgReps[rgReps[iRep].m_iFirst].m_iNormalIdx        = rglNormalIndices[iIndex];
  1758.  
  1759.                         // update face indices
  1760.                         rgFaces[cFaces].m_rgIndices[iIndex] = rgReps[iRep].m_iFirst;
  1761.                     }
  1762.                     else 
  1763.                     {
  1764.                         // append new rep 
  1765.  
  1766.                         if (cReps >= cRepsMax) 
  1767.                         {
  1768.                             // double array size
  1769.                             cRepsMax += cRepsMax;
  1770.  
  1771.                             Rep*    rgNewReps    = new Rep[cRepsMax];
  1772.  
  1773.                             ASSERT(rgNewReps,
  1774.                                         "Could not allocate memory for new rep array");
  1775.  
  1776.                             memcpy(rgNewReps, rgReps, cReps * sizeof(Rep));
  1777.  
  1778.                             delete[] rgReps;
  1779.  
  1780.                             rgReps      = rgNewReps;
  1781.                         }
  1782.  
  1783.                         // create new rep at the end of the array
  1784.                         rgReps[cReps].m_iTexCoordIdx    = rglTexCoordIndices[iIndex];
  1785.                         rgReps[cReps].m_iNormalIdx        = rglNormalIndices[iIndex];
  1786.                         rgReps[cReps].m_iFirst            = rgReps[iRep].m_iFirst;
  1787.                         rgReps[cReps].m_iNext            = rgReps[iRep].m_iFirst;
  1788.  
  1789.                         rgReps[iRep].m_iNext            = cReps;
  1790.  
  1791.                         // increment rep count at the first rep
  1792.                         rgReps[rgReps[iRep].m_iFirst].m_cReps++;
  1793.  
  1794.  
  1795.                         // update face indices
  1796.                         rgFaces[cFaces].m_rgIndices[iIndex] = cReps;    
  1797.  
  1798.                         cReps++;
  1799.                     }
  1800.                 }
  1801.             }
  1802.  
  1803.             cFaces++;
  1804.         }
  1805.     }
  1806.  
  1807.  
  1808.  
  1809.  
  1810.  
  1811.  
  1812.  
  1813.             
  1814.  
  1815.     
  1816.     // skinning info
  1817.             
  1818.  
  1819.     MObject    objShape;
  1820.     MObject objTransform;
  1821.     MObject    objInput;
  1822.  
  1823.     DT_ATTEMPT(DtExt_ShapeGetShapeNode(iShape, objShape));
  1824.     DT_ATTEMPT(DtExt_ShapeGetTransform(iShape, objTransform));
  1825.  
  1826.  
  1827.  
  1828.  
  1829.     // load the mesh's world transform (needed if skinning info is found)
  1830.     MDagPath    pathTransform;
  1831.  
  1832.     MFnDagNode(objTransform).getPath(pathTransform);
  1833.  
  1834.     MMatrix        matMeshWorldTransform    = pathTransform.inclusiveMatrix();
  1835.  
  1836.  
  1837.  
  1838.  
  1839.  
  1840.     cBones                = 0;
  1841.     rgBones                = NULL;
  1842.  
  1843.     cMaxBonesPerVertex    = 0;
  1844.     cMaxBonesPerFace    = 0;
  1845.  
  1846.  
  1847.     MObjectArray    rgobjBones;
  1848.  
  1849.  
  1850.  
  1851.  
  1852.  
  1853.  
  1854.  
  1855.     // smooth skinning
  1856.  
  1857.     bool*    rgbNonZeroFlagTable    = NULL;        // table of influences vs. vertices
  1858.     int*    rgcNonZeros            = NULL;        // array of influence counts 
  1859.  
  1860.     bool bFoundSmoothSkin    = false;
  1861.  
  1862.     if (objShape.hasFn(MFn::kMesh))         // if this shape is a mesh
  1863.     {
  1864.         // loop through skin clusters
  1865.         for (MItDependencyNodes itSkin(MFn::kSkinClusterFilter); !itSkin.isDone(); itSkin.next()) 
  1866.         {
  1867.             MFnSkinCluster fnSkin(itSkin.item());
  1868.  
  1869.             // load input and output geometries
  1870.             MObjectArray    rgInputs;
  1871.             MObjectArray    rgOutputs;
  1872.  
  1873.             fnSkin.getInputGeometry(rgInputs);
  1874.             fnSkin.getOutputGeometry(rgOutputs);
  1875.  
  1876.             assert(rgInputs.length() == rgOutputs.length());        // ensure that input geometry count 
  1877.                                                                     // equals output geometry count
  1878.  
  1879.             int    cInputs, cOutputs;
  1880.  
  1881.             cInputs    = cOutputs    = (int)rgOutputs.length();
  1882.  
  1883.             // loop through the output geometries
  1884.             for (int iOutput = 0, iInput = 0; iOutput < cOutputs; iOutput++, iInput++) 
  1885.             {
  1886.                 assert(iOutput == iInput);        // sanity check
  1887.  
  1888.                 
  1889.                 if (rgOutputs[iOutput] == objShape)         // if our shape is one of the output geometries
  1890.                 {
  1891.                     MDagPathArray    rgdagpathInfluences;
  1892.                     
  1893.                     cBones    = (int)fnSkin.influenceObjects(rgdagpathInfluences, &mStat);
  1894.  
  1895.                     rgBones    = new Bone[cBones];
  1896.  
  1897.                     ASSERT(rgBones,
  1898.                                 "Could not allocate memory for bone array");
  1899.  
  1900.  
  1901.                     // initialize bones
  1902.                     for (int iBone = 0; iBone < cBones; iBone++) 
  1903.                     {    // WARNING: not checking for new failure
  1904.                         rgBones[iBone].m_szName            = new char[256];
  1905.                         rgBones[iBone].m_cReps            = 0;
  1906.                         rgBones[iBone].m_cWeights        = 0;
  1907.                         rgBones[iBone].m_rgiVertices    = new int[cVertices];
  1908.                         rgBones[iBone].m_rgfWeights        = new float[cVertices];
  1909.  
  1910.                         g_Strings.add(rgBones[iBone].m_szName);        // housekeeping
  1911.  
  1912.                         // bone name
  1913.                         strcpy(rgBones[iBone].m_szName, rgdagpathInfluences[iBone].partialPathName().asChar());
  1914.  
  1915.                         // matrix offset
  1916.                         MFnIkJoint fnBone(rgdagpathInfluences[iBone]);
  1917.  
  1918.                         MObject objBindPose;
  1919.  
  1920.                         fnBone.findPlug("bindPose").getValue(objBindPose);
  1921.  
  1922.                         MFnMatrixData fnBindPose(objBindPose);
  1923.  
  1924.                         (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iBone].m_matOffset);
  1925.  
  1926.  
  1927.  
  1928.                         rgobjBones.append(rgdagpathInfluences[iBone].node());
  1929.                     }
  1930.  
  1931.                     rgcNonZeros            = new int[cVertices];
  1932.  
  1933.                     ASSERT(rgcNonZeros,
  1934.                                 "Could not allocate memory for non zero count array");
  1935.  
  1936.                     rgbNonZeroFlagTable    = new bool[cVertices * cBones];
  1937.  
  1938.                     ASSERT(rgbNonZeroFlagTable,
  1939.                                 "Could not allocate memory for non zero table");
  1940.  
  1941.                     // bone info; calculate max number of bones per vertex
  1942.                     cMaxBonesPerVertex = 0;
  1943.  
  1944.                     int iVertex = 0;
  1945.  
  1946.                     MFnMesh fnOutput(rgOutputs[iOutput]);
  1947.  
  1948.                     MDagPath dagpathOutputShape;
  1949.                 
  1950.                     fnOutput.getPath(dagpathOutputShape);
  1951.  
  1952.                     // loop through the vertices
  1953.                     for (MItGeometry itGeom(rgOutputs[iOutput]); !itGeom.isDone(); itGeom.next()) 
  1954.                     {
  1955.                         MFloatArray rgfWeights;
  1956.  
  1957.                         unsigned cInfs;
  1958.  
  1959.                         fnSkin.getWeights(dagpathOutputShape, itGeom.component(), rgfWeights, cInfs);
  1960.  
  1961.                         assert(rgdagpathInfluences.length() == rgfWeights.length());
  1962.                         assert(rgfWeights.length() == cInfs);
  1963.  
  1964.                         rgcNonZeros[iVertex] = 0;
  1965.  
  1966.  
  1967.                         float fWeightSum = 0.0f;
  1968.  
  1969.                         for (int iBone = 0; iBone < cBones; iBone++)
  1970.                             fWeightSum += rgfWeights[iBone];
  1971.  
  1972.                         assert(fWeightSum > 0.00001f);
  1973.  
  1974.                         for (iBone = 0; iBone < cBones; iBone++) 
  1975.                         {
  1976.                             rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = false;
  1977.  
  1978.                             rgfWeights[iBone] = rgfWeights[iBone] / fWeightSum;        // normalize the weight
  1979.  
  1980.                             if (rgfWeights[iBone] != 0.0f) 
  1981.                             {
  1982.                                 rgcNonZeros[iVertex]++;
  1983.  
  1984.                                 rgBones[iBone].m_cReps += rgReps[iVertex].m_cReps;
  1985.         
  1986.                                 rgBones[iBone].m_rgiVertices[rgBones[iBone].m_cWeights]    = iVertex;                            
  1987.                                 rgBones[iBone].m_rgfWeights[rgBones[iBone].m_cWeights]    = rgfWeights[iBone];
  1988.  
  1989.                                 rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = true;
  1990.  
  1991.                                 rgBones[iBone].m_cWeights++;
  1992.                             }
  1993.                         }
  1994.  
  1995.  
  1996.                         if (rgcNonZeros[iVertex] > cMaxBonesPerVertex)
  1997.                             cMaxBonesPerVertex = rgcNonZeros[iVertex];
  1998.  
  1999.                         iVertex++;
  2000.                     }
  2001.  
  2002.  
  2003.  
  2004.                     // calculate max number of bones per vertex
  2005.  
  2006.                     cMaxBonesPerFace    = 0;
  2007.  
  2008.                     for (int iFace = 0; iFace < cFaces; iFace++) 
  2009.                     {
  2010.                         int    cBonesPerFace    = 0;
  2011.  
  2012.                         for (int iBone = 0; iBone < cBones; iBone++) 
  2013.                         {
  2014.                             for (int iIndex = 0; iIndex < rgFaces[iFace].m_cIndices; iIndex++) 
  2015.                             {
  2016.                                 if (rgbNonZeroFlagTable[iBone * cVertices + rgReps[rgFaces[iFace].m_rgIndices[iIndex]].m_iFirst]) 
  2017.                                 {
  2018.                                     cBonesPerFace++;
  2019.  
  2020.                                     break;
  2021.                                 }
  2022.                             }
  2023.                         }
  2024.  
  2025.                         if (cBonesPerFace > cMaxBonesPerFace)
  2026.                             cMaxBonesPerFace = cBonesPerFace;
  2027.                     }
  2028.  
  2029.  
  2030.  
  2031.  
  2032.  
  2033.                     objInput = rgInputs[iInput];
  2034.  
  2035.                     bFoundSmoothSkin = true;
  2036.  
  2037.                     break;
  2038.                 }
  2039.             }
  2040.  
  2041.             if (bFoundSmoothSkin)
  2042.                 break;
  2043.         }
  2044.     }
  2045.  
  2046.  
  2047.     delete[] rgcNonZeros;
  2048.     delete[] rgbNonZeroFlagTable;
  2049.  
  2050.  
  2051.  
  2052.  
  2053.  
  2054.  
  2055.  
  2056.  
  2057.  
  2058.  
  2059.  
  2060.  
  2061.  
  2062.  
  2063.  
  2064.  
  2065.  
  2066.     // rigid skinning
  2067.  
  2068.     rgbNonZeroFlagTable    = NULL;
  2069.  
  2070.     bool    bFoundRigidSkin    = false;
  2071.  
  2072.     if (!bFoundSmoothSkin && objShape.hasFn(MFn::kMesh))     // shape is a mesh 
  2073.     {
  2074.         cBones            = 1;                        // zero'th bone is the extra "fake" bone
  2075.         int cBonesMax    = 64;
  2076.         rgBones            = new Bone[cBonesMax];
  2077.  
  2078.         ASSERT(rgBones,
  2079.                     "Could not allocate memory for bone array");
  2080.  
  2081.         rgbNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  2082.  
  2083.         ASSERT(rgbNonZeroFlagTable,
  2084.                     "Could not allocate memory for non-zero flag table");
  2085.  
  2086.         // fill non zero table with 0's
  2087.         memset(rgbNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  2088.  
  2089.         // initialize "fake" iBone
  2090.         // WARNING: not checking for new failure
  2091.         rgBones[0].m_szName            = new char[256];
  2092.         rgBones[0].m_cReps            = 0;
  2093.         rgBones[0].m_cWeights        = 0;
  2094.         rgBones[0].m_rgfWeights        = new float[cVertices];
  2095.         rgBones[0].m_rgiVertices    = new int[cVertices];
  2096.  
  2097.         g_Strings.add(rgBones[0].m_szName);                            // housekeeping
  2098.  
  2099.         strcpy(rgBones[0].m_szName, SCENE_ROOT);                    // bone name
  2100.     
  2101.         matMeshWorldTransform.get(rgBones[0].m_matOffset);            // "fake" bone has identity matrix
  2102.  
  2103.  
  2104.         // loop through joint clusters
  2105.         for (MItDependencyNodes itCluster(MFn::kJointCluster); !itCluster.isDone(); itCluster.next()) 
  2106.         {
  2107.             MFnWeightGeometryFilter fnCluster(itCluster.item());
  2108.  
  2109.             // load input and output geometries
  2110.             MObjectArray    rgInputs;
  2111.             MObjectArray    rgOutputs;
  2112.  
  2113.             fnCluster.getInputGeometry(rgInputs);
  2114.             fnCluster.getOutputGeometry(rgOutputs);
  2115.  
  2116.             assert(rgInputs.length() == rgOutputs.length());    // ensure input geometry count equals 
  2117.                                                                 // output geometry count
  2118.  
  2119.             int    cInputs, cOutputs;
  2120.  
  2121.             cInputs    = cOutputs    
  2122.                 = (int)rgOutputs.length();
  2123.  
  2124.             // loop through the output geometries
  2125.             for (int iOutput = 0, iInput = 0; iOutput < cOutputs; iOutput++, iInput++) 
  2126.             {
  2127.                 assert(iOutput == iInput);
  2128.                 
  2129.                 if (rgOutputs[iOutput] == objShape)     // our shape is one of the output geometries
  2130.                 {
  2131.                     bFoundRigidSkin    = true;
  2132.         
  2133.                     assert(rgInputs[iInput] == fnCluster.inputShapeAtIndex(iInput));    // sanity check
  2134.  
  2135.                     objInput    = rgInputs[iInput];
  2136.  
  2137.                     // get bone
  2138.                     MPlug        plgMatrix    = fnCluster.findPlug("matrix", &mStat);
  2139.  
  2140.                     MPlugArray    rgplgMatrixConnections;
  2141.  
  2142.                     plgMatrix.connectedTo(rgplgMatrixConnections, true, false);            // get source plugs
  2143.                     assert(rgplgMatrixConnections.length() == 1);
  2144.  
  2145.                     MObject    objBone    = rgplgMatrixConnections[0].node();
  2146.  
  2147.                     assert(objBone.hasFn(MFn::kJoint));
  2148.  
  2149.                     MFnIkJoint fnBone(objBone);
  2150.  
  2151.                     char    szBone[64];
  2152.  
  2153.                     strcpy(szBone, fnBone.name().asChar());
  2154.  
  2155.                     // find bone's index in current bone list
  2156.                     for (int iBone = 1; iBone < cBones;    iBone++) 
  2157.                     {
  2158.                         if (!strcmp(rgBones[iBone].m_szName, szBone))
  2159.                             break;
  2160.                     }
  2161.     
  2162.                     if (iBone == cBones)     // bone was not found in current bone list
  2163.                     {
  2164.                         // add bone
  2165.                         if (cBones >= cBonesMax) 
  2166.                         {
  2167.                             // double array size
  2168.                             cBonesMax  += cBonesMax;
  2169.  
  2170.                             Bone*    rgNewBones    = new Bone[cBonesMax];
  2171.  
  2172.                             ASSERT(rgNewBones, 
  2173.                                         "Could not allocate memory for new bone array");
  2174.  
  2175.                             memcpy(rgNewBones, rgBones, cBones * sizeof(Bone));
  2176.  
  2177.                             delete[] rgBones;
  2178.  
  2179.                             rgBones    = rgNewBones;
  2180.  
  2181.  
  2182.                             bool*    rgbNewNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  2183.  
  2184.                             ASSERT(rgbNewNonZeroFlagTable, 
  2185.                                         "Could not allocate memory for new non-zero flag table");
  2186.  
  2187.                             memset(rgbNewNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  2188.                             memcpy(rgbNewNonZeroFlagTable, rgbNonZeroFlagTable, cBones * cVertices * sizeof(bool));
  2189.  
  2190.                             delete[] rgbNonZeroFlagTable;
  2191.  
  2192.                             rgbNonZeroFlagTable    = rgbNewNonZeroFlagTable;
  2193.                         }
  2194.         
  2195.                         // initialize iBone
  2196.                         // WARNING: not checking for new failure
  2197.                         rgBones[iBone].m_szName            = new char[256];
  2198.                         rgBones[iBone].m_cReps            = 0;
  2199.                         rgBones[iBone].m_cWeights        = 0;
  2200.                         rgBones[iBone].m_rgiVertices    = new int[cVertices];
  2201.                         rgBones[iBone].m_rgfWeights        = new float[cVertices];
  2202.  
  2203.                         g_Strings.add(rgBones[iBone].m_szName);                            // housekeeping
  2204.  
  2205.                         strcpy(rgBones[iBone].m_szName, szBone);                        // bone name
  2206.     
  2207.                         // matrix info
  2208.                         MObject objBindPose;
  2209.  
  2210.                         fnBone.findPlug("bindPose").getValue(objBindPose);
  2211.  
  2212.                         MFnMatrixData fnBindPose(objBindPose);
  2213.  
  2214.                         (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iBone].m_matOffset);
  2215.  
  2216.  
  2217.                         rgobjBones.append(objBone);
  2218.  
  2219.                         cBones++;
  2220.                     }
  2221.  
  2222.  
  2223.  
  2224.                     char    szParent[64];
  2225.  
  2226.                     bool    bFoundParent    = false;
  2227.                     MObject    objParent;
  2228.  
  2229.                     for (int iParent = 0; iParent < (int)fnBone.parentCount(); iParent++) 
  2230.                     {
  2231.                         objParent    = fnBone.parent(iParent);
  2232.  
  2233.                         MFnDagNode    fnParent(objParent);
  2234.                         
  2235.                         strcpy(szParent, fnParent.name().asChar());        // parent's name
  2236.  
  2237.                         for (int iShape_ = 0; iShape_ < DtShapeGetCount(); iShape_++) 
  2238.                         {
  2239.                             char*    szShape;
  2240.  
  2241.                             DT_ATTEMPT(DtShapeGetName(iShape_, &szShape));
  2242.  
  2243.                             if (!strcmp(szParent, szShape)) 
  2244.                             {
  2245.                                 bFoundParent    = true;
  2246.  
  2247.                                 break;
  2248.                             }
  2249.                         }
  2250.  
  2251.                         if (bFoundParent)
  2252.                             break;
  2253.                     }
  2254.  
  2255.                     iParent    = 0;
  2256.  
  2257.                     if (bFoundParent)     // parent shape found
  2258.                     {
  2259.                         // find parent bone's index in current bone list
  2260.                         for (iParent = 1; iParent < cBones;    iParent++) 
  2261.                         {
  2262.                             if (!strcmp(rgBones[iParent].m_szName, szParent)) 
  2263.                             {
  2264.                                 break;
  2265.                             }
  2266.                         }
  2267.  
  2268.  
  2269.                         if (iParent == cBones)         // parent bone was not found in current bone list
  2270.                         {
  2271.                             // add parent bone
  2272.                             if (cBones >= cBonesMax) 
  2273.                             {
  2274.                                 // double array size
  2275.                                 cBonesMax  += cBonesMax;
  2276.  
  2277.                                 Bone*    rgNewBones    = new Bone[cBonesMax];
  2278.  
  2279.                                 ASSERT(rgNewBones, 
  2280.                                             "Could not allocate memory for new bone array");
  2281.     
  2282.                                 memcpy(rgNewBones, rgBones, cBones * sizeof(Bone));
  2283.     
  2284.                                 delete[] rgBones;
  2285.  
  2286.                                 rgBones    = rgNewBones;
  2287.  
  2288.                                 
  2289.                                 bool*    rgbNewNonZeroFlagTable    = new bool[cBonesMax * cVertices];
  2290.  
  2291.                                 ASSERT(rgbNewNonZeroFlagTable, 
  2292.                                             "Could not allocate memory for new non-zero flag table");
  2293.  
  2294.                                 memset(rgbNewNonZeroFlagTable, 0, cBonesMax * cVertices * sizeof(bool));
  2295.                                 memcpy(rgbNewNonZeroFlagTable, rgbNonZeroFlagTable, cBones * cVertices * sizeof(bool));
  2296.  
  2297.                                 delete[] rgbNonZeroFlagTable;
  2298.  
  2299.                                 rgbNonZeroFlagTable    = rgbNewNonZeroFlagTable;
  2300.                             }
  2301.             
  2302.                             // initialize iBone
  2303.                             // WARNING: not checking for new failure
  2304.                             rgBones[iParent].m_szName        = new char[256];
  2305.                             rgBones[iParent].m_cReps        = 0;
  2306.                             rgBones[iParent].m_cWeights        = 0;
  2307.                             rgBones[iParent].m_rgiVertices    = new int[cVertices];
  2308.                             rgBones[iParent].m_rgfWeights    = new float[cVertices];
  2309.     
  2310.                             g_Strings.add(rgBones[iParent].m_szName);                        // housekeeping
  2311.     
  2312.                             strcpy(rgBones[iParent].m_szName, szParent);        // bone name
  2313.  
  2314.                             // matrix info
  2315.                             MObject    objBindPose;
  2316.     
  2317.                             assert(objParent.hasFn(MFn::kJoint));
  2318.  
  2319.                             MFnIkJoint(objParent).findPlug("bindPose").getValue(objBindPose);
  2320.     
  2321.                             MFnMatrixData fnBindPose(objBindPose);
  2322.     
  2323.                             (matMeshWorldTransform * fnBindPose.matrix().inverse()).get(rgBones[iParent].m_matOffset);
  2324.  
  2325.  
  2326.                             rgobjBones.append(objParent);
  2327.  
  2328.                             cBones++;
  2329.                         }
  2330.                     }
  2331.  
  2332.  
  2333.                     // load weights
  2334.                     MPlug        plgMessage    = fnCluster.findPlug("message");
  2335.  
  2336.                     MPlugArray    rgplgMessageConnections;
  2337.  
  2338.                     plgMessage.connectedTo(rgplgMessageConnections, false, true);    // get destination plugs
  2339.  
  2340.                     assert(rgplgMessageConnections.length() == 1);
  2341.                     assert(rgplgMessageConnections[0].node().hasFn(MFn::kSet));
  2342.  
  2343.                     MFnSet fnSet(rgplgMessageConnections[0].node());
  2344.                 
  2345.                     MSelectionList list;
  2346.  
  2347.                     fnSet.getMembers(list, false);
  2348.  
  2349.                     assert(list.length() == 1);
  2350.  
  2351.                     MDagPath    path;
  2352.                     MObject        objComponents;
  2353.  
  2354.                     list.getDagPath(0, path, objComponents);
  2355.  
  2356.                     MFloatArray    rgWeights;
  2357.  
  2358.                     fnCluster.getWeights(path, objComponents, rgWeights);
  2359.  
  2360.                     MFnSingleIndexedComponent fnComponent(objComponents);
  2361.  
  2362.                     assert (fnComponent.elementCount() == (int)rgWeights.length());
  2363.  
  2364.                     // loop through the weights
  2365.                     for (int iWeight = 0; iWeight < (int)rgWeights.length(); iWeight++) 
  2366.                     {
  2367.                         assert(rgWeights[iWeight] <= 1.0f);
  2368.  
  2369.                         int    iVertex    = fnComponent.element(iWeight);
  2370.                         
  2371.                         rgBones[iBone].m_rgfWeights[rgBones[iBone].m_cWeights]    = rgWeights[iWeight];
  2372.                         rgBones[iBone].m_rgiVertices[rgBones[iBone].m_cWeights]    = iVertex;
  2373.  
  2374.                         rgBones[iBone].m_cReps     += rgReps[iVertex].m_cReps;
  2375.                         rgBones[iBone].m_cWeights++;
  2376.  
  2377.                         rgbNonZeroFlagTable[iBone * cVertices + iVertex]    = true;
  2378.  
  2379.                         if (rgWeights[iWeight] != 1.0f) 
  2380.                         {
  2381.                             rgBones[iParent].m_rgfWeights[rgBones[iParent].m_cWeights]    = 1.0f - rgWeights[iWeight];
  2382.                             rgBones[iParent].m_rgiVertices[rgBones[iParent].m_cWeights]    = iVertex;
  2383.  
  2384.                             rgBones[iParent].m_cReps   += rgReps[iVertex].m_cReps;
  2385.                             rgBones[iParent].m_cWeights++;                // IMPORTANT: Don't change line position
  2386.  
  2387.                             rgbNonZeroFlagTable[iParent * cVertices + iVertex]    = true;
  2388.                         }
  2389.                     }
  2390.  
  2391.                     break;
  2392.                 }    // if found our mesh
  2393.             }    // loop thru geom's
  2394.         }    // loop thru joint clusters
  2395.  
  2396.  
  2397.         if (cBones == 1)         // no rigid skinning found
  2398.         {
  2399.             delete[] rgBones[0].m_rgfWeights;
  2400.             delete[] rgBones[0].m_rgiVertices;
  2401.  
  2402.             cBones    = 0;
  2403.         }
  2404.         else 
  2405.         {
  2406.             // at most 2 bones per vertex in rigid skinning (i.e. bone + parent)
  2407.             cMaxBonesPerVertex    = 2;
  2408.  
  2409.             // calculate max number of bones per vertex
  2410.             cMaxBonesPerFace    = 0;
  2411.  
  2412.             for (int iFace = 0; iFace < cFaces; iFace++) 
  2413.             {
  2414.                 int    cBonesPerFace    = 0;
  2415.  
  2416.                 for (int iBone = 0; iBone < cBones; iBone++) 
  2417.                 {
  2418.                     for (int iIndex = 0; iIndex < rgFaces[iFace].m_cIndices; iIndex++) 
  2419.                     {
  2420.                         if (rgbNonZeroFlagTable[iBone * cVertices + rgReps[rgFaces[iFace].m_rgIndices[iIndex]].m_iFirst]) 
  2421.                         {
  2422.                             cBonesPerFace++;
  2423.  
  2424.                             break;
  2425.                         }
  2426.                     }
  2427.                 }
  2428.  
  2429.                 if (cBonesPerFace > cMaxBonesPerFace)
  2430.                     cMaxBonesPerFace = cBonesPerFace;
  2431.             }
  2432.  
  2433.  
  2434.  
  2435.             
  2436.             
  2437.             
  2438.             
  2439.         }
  2440.     }
  2441.                 
  2442.                 
  2443.     delete[] rgbNonZeroFlagTable;
  2444.  
  2445.  
  2446.  
  2447.     // load lumps of control vertex data
  2448.  
  2449.     if (cBones == 0)        // no skinning found
  2450.     {
  2451.         DT_ATTEMPT(MyDtShapeGetVertices(iShape, &cVertices, &rgVertices));                // lump of vertices
  2452.         DT_ATTEMPT(MyDtShapeGetNormals(iShape, &cNormals, &rgNormals));                    // lump of normals
  2453.     }
  2454.     else                    // skinning found
  2455.     {
  2456.         DT_ATTEMPT(MyDtShapeGetVertices(objInput, objShape, &cVertices, &rgVertices));    // lump of vertices
  2457.         DT_ATTEMPT(MyDtShapeGetNormals(objInput, objShape, &cNormals, &rgNormals));        // lump of normals
  2458.     }
  2459.  
  2460.     DT_ATTEMPT(MyDtShapeGetTextureVertices(iShape, &cTexCoords, &rgTexCoords));            // lump of texture coords
  2461.     DT_ATTEMPT(MyDtShapeGetVerticesColor(iShape, &cVertexColors, &rgVertexColors));        // lump of vertex colors
  2462.  
  2463.  
  2464.  
  2465.     // mesh type
  2466.  
  2467.     pShape->m_kType                = Mesh::POLY_MESH;
  2468.  
  2469.  
  2470.     EXIT;
  2471.  
  2472.  
  2473.     return    hr;
  2474. }
  2475.  
  2476.  
  2477.  
  2478.  
  2479.  
  2480.  
  2481.  
  2482.  
  2483.  
  2484.  
  2485.  
  2486.  
  2487.  
  2488.  
  2489.  
  2490.  
  2491. HRESULT    LoadShape
  2492.         (
  2493.             int        iShape, 
  2494.             Mesh*    pShape
  2495.         )
  2496. {
  2497.     HRESULT    hr    = S_OK;
  2498.  
  2499.     INIT;
  2500.  
  2501.     if (MyDtShapeIsJoint(iShape)) 
  2502.     {
  2503.         pShape->m_kType    = Mesh::BONE;
  2504.     }
  2505.     else if (g_bExportPatches && MyDtShapeIsPatchMesh(iShape)) 
  2506.     {
  2507.         HR_ATTEMPT(LoadPatchMesh(iShape, pShape),
  2508.             "Could not load patch-mesh");
  2509.     }
  2510.     else 
  2511.     {
  2512.         HR_ATTEMPT(LoadPolyMesh(iShape, pShape),
  2513.             "Could not load poly-mesh");
  2514.     }
  2515.  
  2516.     EXIT;
  2517.  
  2518.     return    hr;
  2519. }
  2520.  
  2521.  
  2522.  
  2523.  
  2524.  
  2525.  
  2526.  
  2527.  
  2528.  
  2529.  
  2530.  
  2531.  
  2532.  
  2533.  
  2534.  
  2535.  
  2536.  
  2537.  
  2538.  
  2539.  
  2540.  
  2541.  
  2542.  
  2543.  
  2544. HRESULT    AddSkin
  2545.         (
  2546.             Mesh*                    pShape, 
  2547.             LPDIRECTXFILEDATA        pShapeDataObject, 
  2548.             LPDIRECTXFILESAVEOBJECT    pxofSave
  2549.         ) 
  2550. {
  2551.     HRESULT    hr    = S_OK;
  2552.  
  2553.  
  2554.     LPDIRECTXFILEDATA    pSkinDataObject    = NULL;
  2555.  
  2556.  
  2557.     PBYTE    pbSkinData    = NULL;
  2558.  
  2559.  
  2560.  
  2561.     INIT;
  2562.  
  2563.  
  2564.  
  2565.     int        cbSkinSize    = sizeof(WORD)        // nMaxSkinWeightsPerVertex
  2566.                         + sizeof(WORD)        // nMaxSkinWeightsPerFace
  2567.                         + sizeof(WORD);        // nBones
  2568.  
  2569.     PBYTE    pbSkinCurr    = pbSkinData    = new BYTE[cbSkinSize];
  2570.  
  2571.     ASSERT(pbSkinData,
  2572.                 "Could not allocate memory for pbSkinData");
  2573.  
  2574.  
  2575.     // nMaxSkinWeightsPerVertex
  2576.     WRITE_WORD(pbSkinCurr, ((WORD)pShape->m_cMaxBonesPerVertex));
  2577.  
  2578.     // nMaxSkinWeightsPerFace
  2579.     WRITE_WORD(pbSkinCurr, ((WORD)pShape->m_cMaxBonesPerFace));
  2580.  
  2581.     // nBones
  2582.     WRITE_WORD(pbSkinCurr, ((WORD)pShape->m_cBones));
  2583.  
  2584.  
  2585.     HR_ATTEMPT(pxofSave->CreateDataObject(DXFILEOBJ_XSkinMeshHeader, NULL, NULL, cbSkinSize, pbSkinData, &pSkinDataObject),
  2586.                 "Could not create pSkinDataObject");
  2587.  
  2588.  
  2589.     HR_ATTEMPT(pShapeDataObject->AddDataObject(pSkinDataObject),
  2590.                 "Could not add pSkinDataObject to pShapeDataObject");
  2591.  
  2592.  
  2593.  
  2594.     EXIT;
  2595.  
  2596.  
  2597.  
  2598.     delete[] pbSkinData;
  2599.  
  2600.     if (pSkinDataObject)
  2601.         pSkinDataObject->Release();
  2602.  
  2603.  
  2604.     if (FAILED(hr))
  2605.         return hr;
  2606.  
  2607.  
  2608.     // SkinWeights
  2609.     for (int iBone = 0; iBone < pShape->m_cBones; iBone++) 
  2610.     {
  2611.         LPDIRECTXFILEDATA    pBoneDataObject    = NULL;
  2612.  
  2613.         PBYTE    pbBoneData    = NULL;
  2614.  
  2615.  
  2616.         INIT;
  2617.  
  2618.         int        cbBoneSize    = sizeof(char*)                                    // transformNodeName
  2619.                             + sizeof(DWORD)                                    // nWeights
  2620.                             + sizeof(DWORD) * pShape->m_rgBones[iBone].m_cReps    // vertexIndices[nWeights]
  2621.                             + sizeof(float) * pShape->m_rgBones[iBone].m_cReps    // weights[nWeights]
  2622.                             + sizeof(float) * 16;                            // matrixOffset
  2623.  
  2624.         PBYTE    pbBoneCurr    = pbBoneData    = new BYTE[cbBoneSize];
  2625.  
  2626.         ASSERT(pbBoneData,
  2627.                     "Could not allocate memory for pbBoneData.");
  2628.  
  2629.  
  2630.         // transformNodeName
  2631.         WRITE_PCHAR(pbBoneCurr, ((char*)pShape->m_rgBones[iBone].m_szName));
  2632.  
  2633.         // nWeights
  2634.         WRITE_DWORD(pbBoneCurr, ((DWORD)pShape->m_rgBones[iBone].m_cReps));
  2635.  
  2636.         // vertexIndices[nWeights]
  2637.         for (int iVertex = 0; iVertex < pShape->m_rgBones[iBone].m_cWeights; iVertex++) 
  2638.         {
  2639.             int iRep = pShape->m_rgBones[iBone].m_rgiVertices[iVertex];
  2640.  
  2641.             do 
  2642.             {
  2643.                 WRITE_DWORD(pbBoneCurr, ((DWORD)iRep));
  2644.  
  2645.                 iRep = pShape->m_rgReps[iRep].m_iNext;
  2646.             } while (iRep != pShape->m_rgReps[iRep].m_iFirst);
  2647.         }
  2648.  
  2649.         // weights[nWeights]
  2650.         for (iVertex = 0; iVertex < pShape->m_rgBones[iBone].m_cWeights; iVertex++)
  2651.         {
  2652.             for (int iRep = 0; iRep < pShape->m_rgReps[pShape->m_rgBones[iBone].m_rgiVertices[iVertex]].m_cReps; iRep++)
  2653.             {
  2654.                 WRITE_FLOAT(pbBoneCurr, pShape->m_rgBones[iBone].m_rgfWeights[iVertex]);
  2655.             }
  2656.         }
  2657.  
  2658.         // matrixOffset
  2659.         for (int iRow = 0; iRow < 4; iRow++)
  2660.         {
  2661.             for (int iCol = 0; iCol < 4; iCol++)
  2662.             {
  2663.                 WRITE_FLOAT(pbBoneCurr, pShape->m_rgBones[iBone].m_matOffset[iRow][iCol]);
  2664.             }
  2665.         }
  2666.  
  2667.  
  2668.         HR_ATTEMPT(pxofSave->CreateDataObject(DXFILEOBJ_SkinWeights, NULL, NULL, cbBoneSize, pbBoneData, &pBoneDataObject),
  2669.                     "Could not create pBoneDataObject");
  2670.  
  2671.  
  2672.         HR_ATTEMPT(pShapeDataObject->AddDataObject(pBoneDataObject),
  2673.                     "Could not add pBoneDataObject to pShapeDataObject");
  2674.  
  2675.  
  2676.  
  2677.         EXIT;
  2678.  
  2679.  
  2680.  
  2681.         delete[] pbBoneData;
  2682.  
  2683.         if (pBoneDataObject)
  2684.             pBoneDataObject->Release();
  2685.  
  2686.  
  2687.         if (FAILED(hr))
  2688.             return hr;
  2689.     }
  2690.  
  2691.  
  2692.     return hr;
  2693. }
  2694.  
  2695.  
  2696.  
  2697.  
  2698.  
  2699.  
  2700.  
  2701.  
  2702.  
  2703.  
  2704. HRESULT    AddNormals
  2705.         (
  2706.             Mesh*                    pShape, 
  2707.             LPDIRECTXFILEDATA        pShapeDataObject, 
  2708.             LPDIRECTXFILESAVEOBJECT pxofSave
  2709.         ) 
  2710. {
  2711.     HRESULT    hr    = S_OK;
  2712.  
  2713.     LPDIRECTXFILEDATA    pNormalsDataObject    = NULL;
  2714.  
  2715.     PBYTE    pbNormalsData    = NULL;
  2716.  
  2717.     INIT;
  2718.     
  2719.     int        cbNormalsSize    = sizeof(DWORD)                                                    // nNormals
  2720.                             + pShape->m_cReps * (3 * sizeof(float))                            // normals
  2721.                             + sizeof(DWORD)                                                    // nFaceNormals
  2722.                             + (pShape->m_cFaces + pShape->m_cFaceIndices) * sizeof(DWORD);    // faceNormals
  2723.  
  2724.     PBYTE    pbNormalsCurr    = pbNormalsData    
  2725.                             = new BYTE[cbNormalsSize];
  2726.  
  2727.     ASSERT(pbNormalsCurr, "Could not allocate memory for pbNormalsData");
  2728.  
  2729.  
  2730.     // nNormals
  2731.     WRITE_DWORD(pbNormalsCurr, ((DWORD)pShape->m_cReps));
  2732.  
  2733.     // normals
  2734.     int iRep;
  2735.  
  2736.     for (iRep = 0; iRep < pShape->m_cReps; iRep++) 
  2737.     {
  2738.         if (pShape->m_rgReps[iRep].m_iNormalIdx == -1)        // no normal index found
  2739.         {
  2740.             WRITE_FLOAT(pbNormalsCurr, 1.0f);
  2741.             WRITE_FLOAT(pbNormalsCurr, 0.0f);
  2742.             WRITE_FLOAT(pbNormalsCurr, 0.0f);
  2743.         }
  2744.         else 
  2745.         {
  2746.             WRITE_FLOAT(pbNormalsCurr, pShape->m_rgNormals[pShape->m_rgReps[iRep].m_iNormalIdx].vec[0]);
  2747.             WRITE_FLOAT(pbNormalsCurr, pShape->m_rgNormals[pShape->m_rgReps[iRep].m_iNormalIdx].vec[1]);
  2748.             WRITE_FLOAT(pbNormalsCurr, pShape->m_rgNormals[pShape->m_rgReps[iRep].m_iNormalIdx].vec[2]);
  2749.         }
  2750.     }
  2751.  
  2752.     // nFaceNormals
  2753.     WRITE_DWORD(pbNormalsCurr, ((DWORD)pShape->m_cFaces));
  2754.  
  2755.     // faceNormals
  2756.     int iFace;
  2757.  
  2758.     for (iFace = 0; iFace < pShape->m_cFaces; iFace++) 
  2759.     {
  2760.         WRITE_DWORD(pbNormalsCurr, ((DWORD)pShape->m_rgFaces[iFace].m_cIndices));
  2761.  
  2762.         for (int iIndex = 0; iIndex < pShape->m_rgFaces[iFace].m_cIndices; iIndex++)
  2763.             WRITE_DWORD(pbNormalsCurr, ((DWORD)pShape->m_rgFaces[iFace].m_rgIndices[iIndex]));
  2764.     }
  2765.  
  2766.  
  2767.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMMeshNormals, NULL, NULL, cbNormalsSize, pbNormalsData, &pNormalsDataObject),
  2768.                 "Could not create normals data object")
  2769.  
  2770.  
  2771.     HR_ATTEMPT(pShapeDataObject->AddDataObject(pNormalsDataObject),
  2772.                 "Could not add pNormalsDataObject to pShapeDataObject")
  2773.  
  2774.  
  2775.  
  2776.     EXIT;
  2777.  
  2778.     // clean up
  2779.     delete[] pbNormalsData;
  2780.  
  2781.     if (pNormalsDataObject)
  2782.         pNormalsDataObject->Release();
  2783.  
  2784.     return hr;
  2785. }
  2786.  
  2787.  
  2788.  
  2789.  
  2790.  
  2791.  
  2792.  
  2793.  
  2794.  
  2795.  
  2796. HRESULT    AddTexCoords
  2797.         (
  2798.             Mesh*                    pShape, 
  2799.             LPDIRECTXFILEDATA        pShapeDataObject, 
  2800.             LPDIRECTXFILESAVEOBJECT    pxofSave
  2801.         ) 
  2802. {
  2803.     HRESULT    hr    = S_OK;
  2804.  
  2805.     LPDIRECTXFILEDATA    pTexCoordsDataObject    = NULL;
  2806.  
  2807.     PBYTE    pbTexCoordsData    = NULL;
  2808.  
  2809.  
  2810.     INIT;
  2811.  
  2812.  
  2813.     int        cbTexCoordsSize    = sizeof(DWORD)                            // nTextureCoords
  2814.                             + pShape->m_cReps * (2 * sizeof(float));    // textureCoords
  2815.  
  2816.     PBYTE    pbTexCoordsCurr    = pbTexCoordsData    = new BYTE[cbTexCoordsSize];
  2817.  
  2818.     ASSERT(pbTexCoordsData,
  2819.                 "Could not allocate memory for pbTexCoordsData");
  2820.  
  2821.  
  2822.     // nTextureCoords
  2823.     WRITE_DWORD(pbTexCoordsCurr, ((DWORD)pShape->m_cReps));
  2824.  
  2825.     // textureCoords
  2826.     for (int iRep = 0; iRep < pShape->m_cReps; iRep++) 
  2827.     {
  2828.         if (pShape->m_rgReps[iRep].m_iTexCoordIdx == -1)
  2829.         {
  2830.             WRITE_FLOAT(pbTexCoordsCurr, 0.0f);
  2831.             WRITE_FLOAT(pbTexCoordsCurr, 0.0f);
  2832.         }
  2833.         else 
  2834.         {
  2835.             WRITE_FLOAT(pbTexCoordsCurr, g_iFlipU * pShape->m_rgTexCoords[pShape->m_rgReps[iRep].m_iTexCoordIdx].vec[0]);
  2836.             WRITE_FLOAT(pbTexCoordsCurr, g_iFlipV * pShape->m_rgTexCoords[pShape->m_rgReps[iRep].m_iTexCoordIdx].vec[1]);
  2837.         }
  2838.     }
  2839.  
  2840.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMMeshTextureCoords, NULL, NULL, cbTexCoordsSize, pbTexCoordsData, &pTexCoordsDataObject),
  2841.                 "Could not create pTexCoordsDataObject");
  2842.  
  2843.  
  2844.     HR_ATTEMPT(pShapeDataObject->AddDataObject(pTexCoordsDataObject),
  2845.                 "Could not add data object");
  2846.  
  2847.  
  2848.     EXIT;
  2849.  
  2850.  
  2851.     delete[] pbTexCoordsData;
  2852.  
  2853.     if (pTexCoordsDataObject)
  2854.         pTexCoordsDataObject->Release();
  2855.  
  2856.     return hr;
  2857. }
  2858.  
  2859.  
  2860.  
  2861.  
  2862.  
  2863.  
  2864.  
  2865. HRESULT    AddMaterialList
  2866.         (
  2867.             Mesh*                    pShape, 
  2868.             LPDIRECTXFILEDATA        pShapeDataObject, 
  2869.             LPDIRECTXFILESAVEOBJECT    pxofSave
  2870.         ) 
  2871. {
  2872.     HRESULT                hr                        = S_OK;
  2873.  
  2874.     LPDIRECTXFILEDATA    pMaterialsDataObject    = NULL;
  2875.  
  2876.     PBYTE                pbMaterialsData            = NULL;
  2877.     
  2878.     INIT;
  2879.  
  2880.     int        cbMaterialsSize    = sizeof(DWORD)                        // nMaterials
  2881.                             + sizeof(DWORD)                        // nFaceIndexes
  2882.                             + pShape->m_cFaces * sizeof(DWORD);    // FaceIndexes
  2883.  
  2884.     PBYTE    pbMaterialsCurr    = pbMaterialsData    = new BYTE[cbMaterialsSize];
  2885.  
  2886.     ASSERT(pbMaterialsCurr, 
  2887.                 "Could not allocate memory for pbMaterialsData");
  2888.  
  2889.  
  2890.     // nMaterials
  2891.     WRITE_DWORD(pbMaterialsCurr, ((DWORD)pShape->m_cGroups));
  2892.  
  2893.     // nFaceIndexes
  2894.     WRITE_DWORD(pbMaterialsCurr, ((DWORD)pShape->m_cFaces));
  2895.  
  2896.     // FaceIndexes
  2897.     for (int iFace = 0; iFace < pShape->m_cFaces; iFace++)
  2898.         WRITE_DWORD(pbMaterialsCurr, pShape->m_rgFaces[iFace].m_iGroup);
  2899.  
  2900.  
  2901.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMMeshMaterialList, NULL, NULL, cbMaterialsSize, pbMaterialsData, &pMaterialsDataObject),
  2902.                 "Could not create pMaterialsDataObject");
  2903.  
  2904.     // material data
  2905.     for (int iGroup = 0; iGroup < pShape->m_cGroups; iGroup++) 
  2906.     {
  2907.         LPDIRECTXFILEDATA    pMaterialDataObject    = NULL;
  2908.         LPDIRECTXFILEDATA    pTextureDataObject    = NULL;
  2909.  
  2910.         PBYTE                pbMaterialData        = NULL;
  2911.  
  2912.         INIT;
  2913.  
  2914.         int        cbMaterialSize    = 4 * sizeof(float)        // faceColor
  2915.                                 + sizeof(float)            // power
  2916.                                 + 3 * sizeof(float)        // specularColor
  2917.                                 + 3 * sizeof(float);    // emissiveColor
  2918.  
  2919.         PBYTE    pbMaterialCurr    = pbMaterialData    = new BYTE[cbMaterialSize];
  2920.  
  2921.         ASSERT(pbMaterialCurr,
  2922.                     "Could not allocate memory for pbMaterialData");
  2923.  
  2924.  
  2925.         // faceColor
  2926.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fDiffuseRed);
  2927.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fDiffuseGreen);
  2928.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fDiffuseBlue);
  2929.         WRITE_FLOAT(pbMaterialCurr, (1.0f - pShape->m_rgGroups[iGroup].m_fTransparency));
  2930.  
  2931.         // power
  2932.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fShininess);
  2933.         
  2934.         // specularColor
  2935.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fSpecularRed);
  2936.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fSpecularGreen);
  2937.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fSpecularBlue);
  2938.  
  2939.         // emissiveColor
  2940.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fEmissiveRed);
  2941.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fEmissiveGreen);
  2942.         WRITE_FLOAT(pbMaterialCurr, pShape->m_rgGroups[iGroup].m_fEmissiveBlue);
  2943.  
  2944.  
  2945.         HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMMaterial, NULL, NULL, cbMaterialSize, pbMaterialData, &pMaterialDataObject),
  2946.                     "Could not create pMaterialDataObject");
  2947.  
  2948.  
  2949.         // TextureFilename        
  2950.         if (pShape->m_rgGroups[iGroup].m_szTextureFile) 
  2951.         {
  2952.             int        cbTextureSize    = sizeof(char**);
  2953.  
  2954.             HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMTextureFilename, NULL, NULL, cbTextureSize, &pShape->m_rgGroups[iGroup].m_szTextureFile, &pTextureDataObject),
  2955.                         "Could not create pMaterialDataObject");
  2956.  
  2957.             HR_ATTEMPT(pMaterialDataObject->AddDataObject(pTextureDataObject),
  2958.                         "Could not add pTextureDataObject to pMaterialDataObject");
  2959.         }
  2960.  
  2961.  
  2962.         HR_ATTEMPT(pMaterialsDataObject->AddDataObject(pMaterialDataObject),
  2963.                     "Could not add pMaterialDataObject to pMaterialsDataObject");
  2964.  
  2965.  
  2966.         EXIT;
  2967.  
  2968.  
  2969.         delete[] pbMaterialData;
  2970.  
  2971.         if (pMaterialDataObject)
  2972.             pMaterialDataObject->Release();
  2973.  
  2974.         if (pTextureDataObject)
  2975.             pTextureDataObject->Release();
  2976.  
  2977.  
  2978.         ASSERT(SUCCEEDED(hr),    
  2979.                     "Error occured while adding materials");
  2980.     }
  2981.  
  2982.  
  2983.     HR_ATTEMPT(pShapeDataObject->AddDataObject(pMaterialsDataObject),
  2984.                 "Could not add pMaterialsDataObject to pShapeDataObject");
  2985.  
  2986.  
  2987.     EXIT;
  2988.  
  2989.  
  2990.     delete[] pbMaterialsData;
  2991.  
  2992.     if (pMaterialsDataObject)
  2993.         pMaterialsDataObject->Release();    
  2994.     
  2995.         
  2996.     return hr;
  2997. }
  2998.  
  2999.  
  3000.  
  3001.  
  3002.  
  3003.  
  3004.  
  3005.  
  3006. HRESULT    AddVertexColors
  3007.         (
  3008.             Mesh*                    pShape, 
  3009.             LPDIRECTXFILEDATA        pShapeDataObject, 
  3010.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3011.         ) 
  3012. {
  3013.     HRESULT    hr    = S_OK;
  3014.  
  3015.     LPDIRECTXFILEDATA    pColorsDataObject    = NULL;
  3016.  
  3017.     PBYTE    pbColorsData    = NULL;
  3018.     
  3019.  
  3020.     INIT;
  3021.  
  3022.     int        cbColorsSize    = sizeof(DWORD)                                                // nVertexColors
  3023.                             + pShape->m_cReps * (sizeof(DWORD) + 4 * sizeof(float));        // vertexColors
  3024.  
  3025.     PBYTE    pbColorsCurr    = pbColorsData    = new BYTE[cbColorsSize];
  3026.  
  3027.     ASSERT(pbColorsData,
  3028.                 "Could not allocate memory for pbColorsData");
  3029.  
  3030.  
  3031.     // nVertexColors
  3032.     WRITE_DWORD(pbColorsCurr, ((DWORD)pShape->m_cReps));
  3033.  
  3034.     // vertexColors
  3035.     for (int iRep = 0; iRep < pShape->m_cReps; iRep++) 
  3036.     {
  3037.         // index
  3038.         WRITE_DWORD(pbColorsCurr, ((DWORD)iRep));
  3039.  
  3040.         // indexedColor
  3041.         WRITE_FLOAT(pbColorsCurr, pShape->m_rgVertexColors[pShape->m_rgReps[iRep].m_iFirst].r);    // red
  3042.         WRITE_FLOAT(pbColorsCurr, pShape->m_rgVertexColors[pShape->m_rgReps[iRep].m_iFirst].g);    // green
  3043.         WRITE_FLOAT(pbColorsCurr, pShape->m_rgVertexColors[pShape->m_rgReps[iRep].m_iFirst].b);    // blue
  3044.         WRITE_FLOAT(pbColorsCurr, pShape->m_rgVertexColors[pShape->m_rgReps[iRep].m_iFirst].a);    // alpha
  3045.     }
  3046.  
  3047.  
  3048.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMMeshVertexColors, NULL, NULL, cbColorsSize, pbColorsData, &pColorsDataObject),
  3049.                 "Could not create pColorsDataObject");
  3050.  
  3051.  
  3052.     HR_ATTEMPT(pShapeDataObject->AddDataObject(pColorsDataObject),
  3053.                 "Could not add pColorsDataObject to pShapeDataObject");
  3054.  
  3055.  
  3056.     EXIT;
  3057.  
  3058.  
  3059.     delete[] pbColorsData;
  3060.  
  3061.     if (pColorsDataObject)
  3062.         pColorsDataObject->Release();
  3063.  
  3064.  
  3065.     return hr;
  3066. }
  3067.  
  3068.  
  3069.  
  3070.  
  3071.  
  3072.  
  3073.  
  3074.  
  3075.  
  3076.  
  3077.  
  3078. HRESULT    AddRepInfo
  3079.         (
  3080.             Mesh*                    pShape, 
  3081.             LPDIRECTXFILEDATA        pShapeDataObject, 
  3082.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3083.         ) 
  3084. {
  3085.     HRESULT    hr    = S_OK;
  3086.  
  3087.  
  3088.     LPDIRECTXFILEDATA    pRepsDataObject    = NULL;
  3089.  
  3090.  
  3091.     PBYTE    pbRepsData    = NULL;
  3092.     
  3093.     INIT;
  3094.  
  3095.     int        cbRepsSize    = sizeof(DWORD)                        // nIndices
  3096.                         + sizeof(DWORD)                        // nOriginalVertices
  3097.                         + pShape->m_cReps * sizeof(DWORD);    // indices
  3098.  
  3099.     PBYTE    pbRepsCurr    = pbRepsData    = new BYTE[cbRepsSize];
  3100.  
  3101.     ASSERT(pbRepsData,
  3102.                 "Could not allocate memory for pbRepsData");
  3103.  
  3104.  
  3105.     // nIndices
  3106.     WRITE_DWORD(pbRepsCurr, ((DWORD)pShape->m_cReps));
  3107.  
  3108.     // nOriginalVertices
  3109.     WRITE_DWORD(pbRepsCurr, ((DWORD)pShape->m_cVertices));
  3110.  
  3111.     // indices
  3112.     for (int iRep = 0; iRep < pShape->m_cReps; iRep++)
  3113.         WRITE_DWORD(pbRepsCurr, ((DWORD)pShape->m_rgReps[iRep].m_iFirst));
  3114.  
  3115.  
  3116.     HR_ATTEMPT(pxofSave->CreateDataObject(DXFILEOBJ_VertexDuplicationIndices, NULL, NULL, cbRepsSize, pbRepsData, &pRepsDataObject),
  3117.                 "Could not create pRepsDataObject");
  3118.  
  3119.  
  3120.     HR_ATTEMPT(pShapeDataObject->AddDataObject(pRepsDataObject),
  3121.                 "Could not add pRepsDataObject to pShapeDataObject");
  3122.  
  3123.  
  3124.     EXIT;
  3125.  
  3126.  
  3127.     delete[] pbRepsData;
  3128.  
  3129.     if (pRepsDataObject)
  3130.         pRepsDataObject->Release();
  3131.  
  3132.  
  3133.     return hr;
  3134. }
  3135.  
  3136.  
  3137.  
  3138.  
  3139.  
  3140.  
  3141.  
  3142.  
  3143.  
  3144.  
  3145.  
  3146.  
  3147.  
  3148. HRESULT    AddPatchMesh
  3149.         (
  3150.             Mesh*                    pShape, 
  3151.             LPDIRECTXFILEDATA        pFrameDataObject, 
  3152.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3153.         ) 
  3154. {
  3155.  
  3156.     HRESULT    hr    = S_OK;
  3157.  
  3158.     LPDIRECTXFILEDATA    pShapeDataObject    = NULL;
  3159.  
  3160.     PBYTE    pbShapeData    = NULL;
  3161.  
  3162.  
  3163.     INIT;
  3164.  
  3165.  
  3166.     int        cbShapeSize    = sizeof(DWORD)                                                    // nVertices
  3167.                         + pShape->m_cReps * (3 * sizeof(float))                            // vertices
  3168.                         + sizeof(DWORD)                                                    // nPatches
  3169.                         + (pShape->m_cFaces + pShape->m_cFaceIndices) * sizeof(DWORD);    // patches
  3170.  
  3171.     PBYTE    pbShapeCurr    = pbShapeData    = new BYTE[cbShapeSize];
  3172.  
  3173.     ASSERT(pbShapeData,
  3174.                 "Could not allocate memory for pbpShapeData");
  3175.     
  3176.  
  3177.     // nVertices
  3178.     WRITE_DWORD(pbShapeCurr, ((DWORD)pShape->m_cVertices));
  3179.  
  3180.     // vertices
  3181.     for (int iRep = 0; iRep < pShape->m_cReps; iRep++) 
  3182.     {
  3183.         WRITE_FLOAT(pbShapeCurr, pShape->m_rgVertices[pShape->m_rgReps[iRep].m_iFirst].vec[0]);
  3184.         WRITE_FLOAT(pbShapeCurr, pShape->m_rgVertices[pShape->m_rgReps[iRep].m_iFirst].vec[1]);
  3185.         WRITE_FLOAT(pbShapeCurr, pShape->m_rgVertices[pShape->m_rgReps[iRep].m_iFirst].vec[2]);
  3186.     }
  3187.  
  3188.     // nPatches
  3189.     WRITE_DWORD(pbShapeCurr, ((DWORD)pShape->m_cFaces));
  3190.  
  3191.     // faces
  3192.     for (int iFace = 0; iFace < pShape->m_cFaces; iFace++) 
  3193.     {
  3194.         WRITE_DWORD(pbShapeCurr, ((DWORD)16));
  3195.  
  3196.         for (int iIndex = 0; iIndex < 16; iIndex++)
  3197.             WRITE_DWORD(pbShapeCurr, pShape->m_rgFaces[iFace].m_rgIndices[iIndex]);
  3198.     }
  3199.  
  3200.  
  3201.     HR_ATTEMPT(pxofSave->CreateDataObject(DXFILEOBJ_PatchMesh, NULL, NULL, cbShapeSize, pbShapeData, &pShapeDataObject),
  3202.                 "Could not create pShapeDataObject");
  3203.  
  3204.  
  3205.  
  3206.     // MeshTextureCoords
  3207.     if (pShape->m_cTexCoords > 0) 
  3208.     {
  3209.         HR_ATTEMPT(AddTexCoords(pShape, pShapeDataObject, pxofSave),
  3210.                     "Could not add texture coordinate info");
  3211.     }
  3212.  
  3213.     // MeshVertexColors
  3214. //    HR_ATTEMPT(AddVertexColors(pShape, pShapeDataObject, pxofSave),
  3215. //                "Could not add vertex color info");
  3216.     
  3217.     // MeshMaterialList
  3218.     HR_ATTEMPT(AddMaterialList(pShape, pShapeDataObject, pxofSave),
  3219.                 "Could not add materials info");
  3220.  
  3221.     // VertexDuplicationIndices
  3222.     HR_ATTEMPT(AddRepInfo(pShape, pShapeDataObject, pxofSave),
  3223.                 "Could not add rep info");
  3224.  
  3225.     // XSkinMeshHeader
  3226.     if (pShape->m_cBones > 0) 
  3227.     {
  3228.         HR_ATTEMPT(AddSkin(pShape, pShapeDataObject, pxofSave),
  3229.                     "Could not add skin info");
  3230.     }
  3231.  
  3232.  
  3233.  
  3234.     HR_ATTEMPT(pFrameDataObject->AddDataObject(pShapeDataObject),
  3235.                 "Could not add pShapeDataObject to pFrameDataObject");
  3236.  
  3237.  
  3238.     EXIT;
  3239.  
  3240.  
  3241.     delete[] pbShapeData;
  3242.  
  3243.     if (pShapeDataObject)
  3244.         pShapeDataObject->Release();
  3245.  
  3246.  
  3247.     return hr;
  3248. }
  3249.  
  3250.  
  3251.  
  3252.  
  3253.  
  3254.  
  3255.  
  3256.  
  3257.  
  3258.  
  3259.  
  3260.  
  3261.  
  3262.  
  3263.  
  3264.  
  3265. HRESULT    AddPolyMesh
  3266.         (
  3267.             Mesh*                    pShape, 
  3268.             LPDIRECTXFILEDATA        pFrameDataObject, 
  3269.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3270.         ) 
  3271. {
  3272.  
  3273.     HRESULT                hr                = S_OK;
  3274.  
  3275.     LPDIRECTXFILEDATA    pShapeDataObject    = NULL;
  3276.  
  3277.     PBYTE                pbMeshData        = NULL;
  3278.  
  3279.     INIT;
  3280.  
  3281.     int        cbMeshSize    = sizeof(DWORD)                                                    // nVertices
  3282.                         + pShape->m_cReps * (3 * sizeof(float))                            // vertices
  3283.                         + sizeof(DWORD)                                                    // nFaces
  3284.                         + (pShape->m_cFaces + pShape->m_cFaceIndices) * sizeof(DWORD);    // faces
  3285.  
  3286.     PBYTE    pbMeshCurr    = pbMeshData    = new BYTE[cbMeshSize];
  3287.  
  3288.     ASSERT(pbMeshData,
  3289.                 "Could not allocate memory for pbMeshData");
  3290.     
  3291.  
  3292.     // nVertices
  3293.     WRITE_DWORD(pbMeshCurr, ((DWORD)pShape->m_cReps));
  3294.  
  3295.     // vertices
  3296.     for (int iRep = 0; iRep < pShape->m_cReps; iRep++) 
  3297.     {
  3298.         WRITE_FLOAT(pbMeshCurr, pShape->m_rgVertices[pShape->m_rgReps[iRep].m_iFirst].vec[0]);
  3299.         WRITE_FLOAT(pbMeshCurr, pShape->m_rgVertices[pShape->m_rgReps[iRep].m_iFirst].vec[1]);
  3300.         WRITE_FLOAT(pbMeshCurr, pShape->m_rgVertices[pShape->m_rgReps[iRep].m_iFirst].vec[2]);
  3301.     }
  3302.  
  3303.     // nFaces
  3304.     WRITE_DWORD(pbMeshCurr, ((DWORD)pShape->m_cFaces));
  3305.  
  3306.     // faces
  3307.     for (int iFace = 0; iFace < pShape->m_cFaces; iFace++) 
  3308.     {
  3309.         WRITE_DWORD(pbMeshCurr, ((DWORD)pShape->m_rgFaces[iFace].m_cIndices));
  3310.  
  3311.         for (int iIndex = 0; iIndex < pShape->m_rgFaces[iFace].m_cIndices; iIndex++)
  3312.             WRITE_DWORD(pbMeshCurr, ((DWORD)pShape->m_rgFaces[iFace].m_rgIndices[iIndex]));
  3313.     }
  3314.  
  3315.  
  3316.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMMesh, NULL, NULL, cbMeshSize, pbMeshData, &pShapeDataObject),
  3317.                 "Could not create pShapeDataObject");
  3318.  
  3319.  
  3320.     // MeshNormals
  3321.     if (pShape->m_cNormals > 0) 
  3322.     {
  3323.         HR_ATTEMPT(AddNormals(pShape, pShapeDataObject, pxofSave),
  3324.                     "Could not add normal info");
  3325.     }
  3326.  
  3327.  
  3328.     // MeshTextureCoords
  3329.     if (pShape->m_cTexCoords > 0) 
  3330.     {
  3331.         HR_ATTEMPT(AddTexCoords(pShape, pShapeDataObject, pxofSave),
  3332.                     "Could not add texture coordinate info");
  3333.     }
  3334.  
  3335.     // MeshVertexColors
  3336. //    HR_ATTEMPT(AddVertexColors(pShape, pShapeDataObject, pxofSave),
  3337. //                "Could not add vertex color info");
  3338.  
  3339.     
  3340.     // MeshMaterialList
  3341.     HR_ATTEMPT(AddMaterialList(pShape, pShapeDataObject, pxofSave),
  3342.                 "Could not add materials info");
  3343.  
  3344.  
  3345.     // VertexDuplicationIndices
  3346.     HR_ATTEMPT(AddRepInfo(pShape, pShapeDataObject, pxofSave),
  3347.                 "Could not add rep info");
  3348.  
  3349.  
  3350.     // XSkinMeshHeader
  3351.     if (pShape->m_cBones > 0) 
  3352.     {
  3353.         HR_ATTEMPT(AddSkin(pShape, pShapeDataObject, pxofSave),
  3354.                     "Could not add skin info");
  3355.     }
  3356.  
  3357.  
  3358.     HR_ATTEMPT(pFrameDataObject->AddDataObject(pShapeDataObject),
  3359.                 "Could not add pShapeDataObject to pFrameDataObject");
  3360.  
  3361.  
  3362.  
  3363.     EXIT;
  3364.  
  3365.  
  3366.  
  3367.     delete[] pbMeshData;
  3368.  
  3369.     if (pShapeDataObject)
  3370.         pShapeDataObject->Release();
  3371.  
  3372.  
  3373.     return hr;
  3374. }
  3375.  
  3376.  
  3377.  
  3378.  
  3379.  
  3380.  
  3381.  
  3382.  
  3383.  
  3384. HRESULT    AddShape
  3385.         (
  3386.             int                        iShape, 
  3387.             LPDIRECTXFILEDATA        pParentFrameDataObject, 
  3388.             LPDIRECTXFILESAVEOBJECT    pxofSave
  3389.         ) 
  3390. {
  3391.  
  3392.     HRESULT                hr                    = S_OK;
  3393.  
  3394.     LPDIRECTXFILEDATA    pFrameDataObject    = NULL;
  3395.     LPDIRECTXFILEDATA    pMatrixDataObject    = NULL;
  3396.  
  3397.  
  3398.     INIT;
  3399.  
  3400.  
  3401.     // shape name
  3402.     char*    szName;
  3403.  
  3404.     DT_ATTEMPT(DtShapeGetName(iShape, &szName));
  3405.  
  3406.  
  3407.     cout << "\treading " << szName << endl;
  3408.  
  3409.  
  3410.     // local transform
  3411.     float*    rgfLocalTransform;
  3412.  
  3413.     DT_ATTEMPT(DtShapeGetMatrix(iShape, &rgfLocalTransform));
  3414.  
  3415.  
  3416.     // Frame
  3417.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMFrame, szName, NULL, 0, NULL, &pFrameDataObject),
  3418.                 "Could not create pFrameDataObject");
  3419.  
  3420.     // FrameTransformMatrix
  3421.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMFrameTransformMatrix, NULL, NULL, 16 * sizeof(float), rgfLocalTransform, &pMatrixDataObject),
  3422.                 "Could not create pMatrixDataObject");
  3423.  
  3424.  
  3425.  
  3426.     HR_ATTEMPT(pFrameDataObject->AddDataObject(pMatrixDataObject),
  3427.                 "Could not add pMatrixDataObject to pFrameDataObject");
  3428.  
  3429.  
  3430.     // the reason for the braces here is to place Mesh in a local scope so that will be deleted quickly 
  3431.     {    
  3432.         Mesh    mesh;
  3433.  
  3434.         LoadShape(iShape, &mesh);
  3435.  
  3436.         switch (mesh.m_kType) 
  3437.         {
  3438.             case Mesh::PATCH_MESH:
  3439.                 HR_ATTEMPT(AddPatchMesh(&mesh, pFrameDataObject, pxofSave),
  3440.                             "Could not add patch mesh");
  3441.                 break;
  3442.             case Mesh::POLY_MESH:
  3443.                 // DtShapeGetVertexCount returns an error code if cVertices == 0
  3444.                 HR_ATTEMPT(AddPolyMesh(&mesh, pFrameDataObject, pxofSave),
  3445.                             "Could not add mesh");
  3446.                 break;
  3447.             case Mesh::BONE:
  3448.                 break;
  3449.             default:
  3450.                 ASSERT(false, "Unknown shape type");
  3451.                 break;
  3452.         };
  3453.     }    
  3454.  
  3455.     // add children
  3456.     int        cChildren;
  3457.     int*    rgiChildren;
  3458.  
  3459.     DT_ATTEMPT(MyDtShapeGetChildren(iShape, &cChildren, &rgiChildren));
  3460.  
  3461.     for (int iChild = 0; iChild < cChildren; iChild++) 
  3462.     {
  3463.         HR_ATTEMPT(AddShape(rgiChildren[iChild], pFrameDataObject, pxofSave),
  3464.                     "Could not add shape");
  3465.     }
  3466.  
  3467.     delete[] rgiChildren;
  3468.  
  3469.     HR_ATTEMPT(pParentFrameDataObject->AddDataObject(pFrameDataObject),
  3470.                 "Could not add pFrameDataObject to pParentFrameDataObject");
  3471.  
  3472.     EXIT;
  3473.  
  3474.     
  3475.     if (pMatrixDataObject)
  3476.         pMatrixDataObject->Release();
  3477.  
  3478.     if (pFrameDataObject)
  3479.         pFrameDataObject->Release();
  3480.     
  3481.  
  3482.     return hr;
  3483. }
  3484.  
  3485.  
  3486.  
  3487.  
  3488.  
  3489.  
  3490. HRESULT    AddScene
  3491.         (
  3492.             const char*    szFile
  3493.         ) 
  3494. {
  3495.     HRESULT    hr    = S_OK;
  3496.  
  3497.  
  3498.     LPDIRECTXFILE            pxofApi                    = NULL;
  3499.     LPDIRECTXFILESAVEOBJECT    pxofSave                = NULL; 
  3500.  
  3501.     LPDIRECTXFILEDATA        pAnimSetObject            = NULL;
  3502.     LPDIRECTXFILEDATA        pRootFrameObject        = NULL;
  3503.     LPDIRECTXFILEDATA        pRootTransformObject    = NULL;
  3504.  
  3505.     INIT;
  3506.  
  3507.  
  3508.     // Initialize the Dt database 
  3509.     DtExt_SceneInit("scene");
  3510.  
  3511.     DtExt_setJointHierarchy(true);
  3512.     DtExt_setParents(true);
  3513.     DtExt_setOutputTransforms(kTRANSFORMALL);
  3514.     DtExt_setTesselate(kTESSTRI);
  3515.     DtExt_setWalkMode(0);
  3516.     DtExt_setInlineTextures(0);                // jimn; 9/25/00; Don't convert textures
  3517.     DtExt_setOriginalTexture(1);            // jimn; 9/25/00; Use original textures.
  3518. //    DtExt_setSoftTextures(1);
  3519.     DtExt_setOutputCameras(0);
  3520.  
  3521.     DtExt_dbInit();
  3522.  
  3523.  
  3524.     cout << "Exporting to " << szFile << " ..." << endl;
  3525.  
  3526.  
  3527.     // create xofapi object.
  3528.     HR_ATTEMPT(DirectXFileCreate(&pxofApi),
  3529.                 "Could not create xofapi object");
  3530.  
  3531.  
  3532.     // register templates for d3drm.
  3533.     HR_ATTEMPT(pxofApi->RegisterTemplates((LPVOID)D3DRM_XTEMPLATES, D3DRM_XTEMPLATE_BYTES),
  3534.                 "Could not register D3D templates");
  3535.  
  3536.  
  3537.     // register extra templates for skinning info and vertex duplication
  3538.     HR_ATTEMPT(pxofApi->RegisterTemplates((LPVOID)XSKINEXP_TEMPLATES, strlen(XSKINEXP_TEMPLATES)),
  3539.                 "Could not register Skinning and/or Vertex Duplication templates");
  3540.  
  3541.  
  3542.     // create save object.
  3543.     HR_ATTEMPT(pxofApi->CreateSaveObject(szFile, g_FileFormat, &pxofSave),
  3544.                 "Could not create save object");
  3545.  
  3546.  
  3547.     // save templates
  3548.     HR_ATTEMPT(pxofSave->SaveTemplates(3, aIds),
  3549.                 "Could not save templates.");
  3550.  
  3551.  
  3552.     // save file data to the file
  3553.  
  3554.     // first create the SCENE_ROOT Frame
  3555.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMFrame, SCENE_ROOT, NULL, 0, NULL, &pRootFrameObject),
  3556.                 "Could not create pRootFrameObject");
  3557.  
  3558.  
  3559.     // next create the SCENE_ROOT FrameTransformMatrix as the Identity 
  3560.     float rgfIdentity[16] = {1.0f, 0.0f, 0.0f, 0.0f,
  3561.                              0.0f, 1.0f, 0.0f, 0.0f,
  3562.                              0.0f, 0.0f, 1.0f, 0.0f,
  3563.                              0.0f, 0.0f, 0.0f, 1.0f};
  3564.  
  3565.  
  3566.     HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMFrameTransformMatrix, NULL, NULL, 16 * sizeof(float), rgfIdentity, &pRootTransformObject),
  3567.                 "Could not create pRootTransformObject");
  3568.  
  3569.  
  3570.     HR_ATTEMPT(pRootFrameObject->AddDataObject(pRootTransformObject),
  3571.                 "Could not add pRootTransformObject to pRootFrameObject");
  3572.  
  3573.  
  3574.     cout << endl << "Loading scene data..." << endl;
  3575.  
  3576.     int cShapes = DtShapeGetCount();
  3577.  
  3578.     // add all shapes which have no parents
  3579.     for (int iShape = 0; iShape < cShapes; iShape++) 
  3580.     {
  3581.         if (MyDtShapeGetParentID(iShape) == -1) 
  3582.         {
  3583.             HR_ATTEMPT(AddShape(iShape, pRootFrameObject, pxofSave),
  3584.                         "Could not add top level shape");
  3585.         }
  3586.     }
  3587.  
  3588.  
  3589.     cout << "Writing scene data..." << endl;
  3590.  
  3591.     HR_ATTEMPT(pxofSave->SaveData(pRootFrameObject),
  3592.                 "Could not save scene data to file");
  3593.  
  3594.  
  3595.  
  3596.  
  3597.     if (g_bExportAnimation) 
  3598.     {
  3599.         HR_ATTEMPT(pxofSave->CreateDataObject(TID_D3DRMAnimationSet, NULL, NULL, 0, NULL, &pAnimSetObject),
  3600.                     "Could not create pAnimSetObject");
  3601.  
  3602.     
  3603.         cout << endl << "Loading animation data..." << endl;
  3604.  
  3605.         bool    bAnimDataFound    = false;
  3606.  
  3607.         if (g_bKeyframeAnimation) 
  3608.         {
  3609.             for (iShape = 0; iShape < cShapes; iShape++) 
  3610.             {
  3611.                 Anim    anim;
  3612.  
  3613.                 loadAnim(iShape, &anim);
  3614.  
  3615.                 if (anim.m_cKeys > 0) 
  3616.                 {
  3617.                     hr = AddAnim(&anim, pAnimSetObject, pxofSave);
  3618.  
  3619.                     if (FAILED(hr))
  3620.                         break;
  3621.  
  3622.                     bAnimDataFound    = true;
  3623.                 }
  3624.  
  3625.  
  3626.                 freeAnim(&anim);
  3627.  
  3628.                 ASSERT(SUCCEEDED(hr), "Could not add animation data");
  3629.             }
  3630.         }
  3631.         else         // regular animation
  3632.         {
  3633.             Anim*    rgAnims    = new Anim[cShapes];
  3634.  
  3635.             ASSERT(rgAnims,
  3636.                         "Could not allocate memory for large animation array");
  3637.  
  3638.             loadAllAnims(rgAnims);
  3639.  
  3640.             for (int iShape = 0; iShape < cShapes; iShape++) 
  3641.             {
  3642.                 if (rgAnims[iShape].m_cKeys > 0) 
  3643.                 {
  3644.                     hr = AddAnim(&rgAnims[iShape], pAnimSetObject, pxofSave);
  3645.  
  3646.                     if (FAILED(hr))
  3647.                         break; 
  3648.  
  3649.                     bAnimDataFound    = true;
  3650.                 }
  3651.             }
  3652.  
  3653.  
  3654.             freeAllAnims(rgAnims);
  3655.  
  3656.             delete[] rgAnims;
  3657.  
  3658.             ASSERT(SUCCEEDED(hr), "Could not add animation data");
  3659.         }
  3660.  
  3661.         if (bAnimDataFound) 
  3662.         {
  3663.             cout << "Writing animation data..." << endl;
  3664.  
  3665.             HR_ATTEMPT(pxofSave->SaveData(pAnimSetObject),
  3666.                         "Could not save animation data to file");
  3667.         }
  3668.         else 
  3669.         {
  3670.             cout << "Writing skipped (no animation data found)..." << endl;
  3671.         }
  3672.     }
  3673.     else 
  3674.     {
  3675.         cout << endl << "Ignoring animation..." << endl;
  3676.     }
  3677.  
  3678.     EXIT;
  3679.  
  3680.  
  3681.     if (pRootFrameObject)
  3682.         pRootFrameObject->Release();
  3683.  
  3684.     if (pRootTransformObject)
  3685.         pRootTransformObject->Release();
  3686.  
  3687.     if (pAnimSetObject)
  3688.         pAnimSetObject->Release();
  3689.  
  3690.  
  3691.     if (pxofSave) 
  3692.         pxofSave->Release();
  3693.  
  3694.     if (pxofApi)
  3695.         pxofApi->Release();
  3696.  
  3697.  
  3698.  
  3699.     cout << endl;
  3700.  
  3701.     if (FAILED(hr))
  3702.         cout << "There were errors.";
  3703.     else 
  3704.         cout << "Completed successfully.";
  3705.  
  3706.     cout << endl << "...................................................." << endl << endl;
  3707.  
  3708.  
  3709.     cout.flush();
  3710.  
  3711.     // Clean up the allocated memory and internal storage
  3712.     DtExt_CleanUp();
  3713.  
  3714.     return hr;
  3715. }
  3716.  
  3717.  
  3718.  
  3719.  
  3720.  
  3721. void    ParseOptions
  3722.         (
  3723.             MString    sOptions
  3724.         ) 
  3725. {
  3726.     if (sOptions.length() > 0) 
  3727.     {
  3728.         MStringArray    optionList;
  3729.  
  3730.         sOptions.split(';', optionList);
  3731.  
  3732.         // break out all the options.
  3733.         for (int iOption = 0; iOption < (int)optionList.length(); iOption++) 
  3734.         {
  3735.             MStringArray    theOption;
  3736.  
  3737.             optionList[iOption].split('=', theOption);
  3738.  
  3739.             if (theOption.length() > 1) 
  3740.             {
  3741.                 if (theOption[0] == "fileFormat") 
  3742.                 {
  3743.                     if (theOption[1] == "binary") 
  3744.                     {
  3745.                         g_FileFormat    = DXFILEFORMAT_BINARY;
  3746.                     }
  3747.                     else if (theOption[1] == "compressed") 
  3748.                     {
  3749.                         g_FileFormat    = DXFILEFORMAT_COMPRESSED;
  3750.                     }
  3751.                     else    // "text" 
  3752.                     {    
  3753.                         g_FileFormat    = DXFILEFORMAT_TEXT;
  3754.                     }
  3755.                 }
  3756.                 else if (theOption[0] == "exportAnimation") 
  3757.                 {
  3758.                     if (theOption[1] == "false") 
  3759.                     {
  3760.                         g_bExportAnimation    = false;
  3761.                     }
  3762.                     else     // "true"
  3763.                     {
  3764.                         g_bExportAnimation    = true;
  3765.                     }
  3766.                 }
  3767.                 else if (theOption[0] == "keyframeAnimation") 
  3768.                 {
  3769.                     if (theOption[1] == "false") 
  3770.                     {
  3771.                         g_bKeyframeAnimation    = false;
  3772.                     }
  3773.                     else     // "true"
  3774.                     {
  3775.                         g_bKeyframeAnimation    = true;
  3776.                     }
  3777.                 }
  3778.                 else if (theOption[0] == "animateEverything") 
  3779.                 {
  3780.                     if (theOption[1] == "false") 
  3781.                     {
  3782.                         g_bAnimateEverything    = false;
  3783.                     }
  3784.                     else     // "true"
  3785.                     {
  3786.                         g_bAnimateEverything    = true;
  3787.                     }
  3788.                 }
  3789.                 else if (theOption[0] == "frameStep") 
  3790.                 {
  3791.                     g_iFrameStep    = theOption[1].asInt();
  3792.                 }
  3793.                 else if (theOption[0] == "flipU") 
  3794.                 {
  3795.                     if (theOption[1] == "true") 
  3796.                     {
  3797.                         g_iFlipU    = -1;
  3798.                     }
  3799.                     else     // "false"
  3800.                     {
  3801.                         g_iFlipU    = 1;
  3802.                     }
  3803.                 }
  3804.                 else if (theOption[0] == "flipV") 
  3805.                 {
  3806.                     if (theOption[1] == "true") 
  3807.                     {
  3808.                         g_iFlipV    = 1;
  3809.                     }
  3810.                     else     // "false"
  3811.                     {
  3812.                         g_iFlipV    = -1;
  3813.                     }
  3814.                 }
  3815.                 else if (theOption[0] == "exportPatches") 
  3816.                 {
  3817.                     if (theOption[1] == "true") 
  3818.                     {
  3819.                         g_bExportPatches    = true;
  3820.                     }
  3821.                     else     // "false"
  3822.                     {
  3823.                         g_bExportPatches    = false;
  3824.                     }
  3825.                 }
  3826.                 else if (theOption[0] == "relTexFilename")
  3827.                 {
  3828.                     if (theOption[1] == "true") 
  3829.                     {
  3830.                         g_bRelativeTexFile    = true;
  3831.                     }
  3832.                     else     // "false"
  3833.                     {
  3834.                         g_bRelativeTexFile    = false;
  3835.                     }
  3836.                 }
  3837.             }
  3838.         }
  3839.     }
  3840. }
  3841.  
  3842.  
  3843.  
  3844. MStatus    xfileTranslator::writer
  3845.         (    // parameters
  3846.             const MFileObject& file, 
  3847.             const MString& sOptions, 
  3848.             MPxFileTranslator::FileAccessMode mode
  3849.         ) 
  3850. {
  3851.     g_Strings.reset();
  3852.  
  3853.     ParseOptions(sOptions);
  3854.  
  3855.     MString    sFile    = file.fullName();
  3856.  
  3857.     int        iExt    = sFile.rindex('.');
  3858.     MString    sExt    = sFile.substring(iExt, sFile.length() - 1);
  3859.  
  3860.     sFile    = (sExt == ".x" || sExt == ".X") ? sFile : (sFile + ".x");
  3861.  
  3862.     AddScene(sFile.asChar());
  3863.  
  3864.     g_Strings.clear();
  3865.  
  3866.     return MS::kSuccess;
  3867. }
  3868.  
  3869.  
  3870.  
  3871.  
  3872.  
  3873. MStatus    initializePlugin 
  3874.         (    
  3875.             MObject    obj
  3876.         ) 
  3877. {
  3878.     MStatus         status;
  3879.     char            version[256];
  3880.  
  3881.     strcpy(version, "0.3");                // plug-in version
  3882.     strcat(version, ".");
  3883.     strcat(version, DtAPIVersion());
  3884.     
  3885.     MFnPlugin       plugin(obj, "XFile Translator for Maya", version, "Any");
  3886.  
  3887.     // register the translator
  3888.     status = plugin.registerFileTranslator("XFile", "xfileTranslator.rgb", xfileTranslator::creator, "xfileTranslatorOpts", "", true);
  3889.  
  3890.     if (!status)
  3891.         status.perror("registerFileTranslator");
  3892.  
  3893.     return status;
  3894. }
  3895.  
  3896.  
  3897. MStatus    uninitializePlugin
  3898.         (    
  3899.             MObject obj
  3900.         ) 
  3901. {
  3902.     MStatus         status;
  3903.     MFnPlugin       plugin(obj);
  3904.  
  3905.     status = plugin.deregisterFileTranslator("XFile");
  3906.  
  3907.     if (!status)
  3908.         status.perror("deregisterFileTranslator");
  3909.  
  3910.     return status;
  3911. }
  3912.  
  3913.  
  3914.  
  3915.  
  3916.  
  3917. /*** TOOLS
  3918.  
  3919.     // print out the attributes of a dependency node
  3920.     for (unsigned iAttr = 0; iAttr < fnNode.attributeCount(); iAttr++) 
  3921.     {
  3922.         MFnAttribute fnAttr(fnNode.attribute(iAttr));
  3923.  
  3924.         cout << fnNode.name() << "." << fnAttr.name() << ": " << fnNode.attribute(iAttr).apiTypeStr() << endl;
  3925.     }
  3926.  
  3927.  
  3928.  
  3929.  
  3930.  
  3931.     // print the node containing the corresponging plug to 'plug'
  3932.     MPlugArray rgPlugs;
  3933.  
  3934.     plug.connectedTo(rgPlugs, true, true);
  3935.  
  3936.     for (int i = 0; i < (int)rgPlugs.length(); i++) 
  3937.     {
  3938.         MFnDependencyNode fnNode(rgPlugs[i].node());
  3939.  
  3940.         cout << fnNode.name() << "\t" << rgPlugs[i].name() << endl;
  3941.     }
  3942.  ***/